Compare commits
2 commits
8a64fe3496
...
a5b8712ec8
Author | SHA1 | Date | |
---|---|---|---|
Jeremy Penner | a5b8712ec8 | ||
Jeremy Penner | 70f2d0338a |
26
body.html
26
body.html
|
@ -15,7 +15,6 @@
|
|||
line-height:1.2
|
||||
}
|
||||
</style>
|
||||
<script src="index.js?v=4"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="filename"></h1>
|
||||
|
@ -33,7 +32,10 @@
|
|||
</div>
|
||||
<div id="errors"></div>
|
||||
<a href="index.html">Back</a>
|
||||
<script>
|
||||
<script type="module">
|
||||
import { decodeBody, choreographyActions } from "./codec.js"
|
||||
import { docBuilder, decodeBinary, showAll, actionShower, limbAnimationShower, celShower, textNode } from "./show.js"
|
||||
|
||||
const propFilter = (key, value) => {
|
||||
if (key != "bitmap" && key != "data" && key != "canvas") {
|
||||
return value
|
||||
|
@ -51,31 +53,31 @@
|
|||
const q = new URLSearchParams(window.location.search)
|
||||
const filename = q.get("f")
|
||||
document.getElementById("filename").innerText = filename
|
||||
const doc = docBuilder({ errorContainer: document.getElementById("errors") })
|
||||
try {
|
||||
const body = await decodeBinary(filename, BodyImpl)
|
||||
const body = await decodeBinary(filename, decodeBody)
|
||||
dumpProp(body, document.getElementById("data"))
|
||||
if (body.error) {
|
||||
showError(body.error, filename)
|
||||
doc.showError(body.error, filename)
|
||||
} else {
|
||||
const celContainer = document.getElementById("cels")
|
||||
const limbContainer = document.getElementById("limbs")
|
||||
for (const [ilimb, limb] of body.limbs.entries()) {
|
||||
labelLimb(celContainer, ilimb)
|
||||
showCels(limb, celContainer)
|
||||
labelLimb(celContainer, ilimb)
|
||||
showAll(doc, celContainer, filename, limb.cels, celShower())
|
||||
|
||||
labelLimb(limbContainer, ilimb)
|
||||
showAnimations(limb, limbContainer, LimbImpl)
|
||||
showAll(doc, limbContainer, filename, limb.animations, limbAnimationShower(limb))
|
||||
}
|
||||
const actionContainer = document.getElementById("actions")
|
||||
for (const action of choreographyActions) {
|
||||
showAll(doc, actionContainer, filename, choreographyActions, (action) => {
|
||||
if (action == "stand" || body.actions[action] != body.actions["stand"]) {
|
||||
actionContainer.appendChild(textNode(action, "div"))
|
||||
actionContainer.appendChild(createAnimation(action, body, BodyImpl))
|
||||
return [textNode(action, "div"), actionShower(body)(action)]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
showError(e, filename)
|
||||
doc.showError(e, filename)
|
||||
}
|
||||
}
|
||||
onload()
|
||||
|
|
497
codec.js
Normal file
497
codec.js
Normal file
|
@ -0,0 +1,497 @@
|
|||
const LE = true // little-endian
|
||||
|
||||
// JS bitmap format: array of scanlines, each scanline being an array of numbers from 0-3
|
||||
export const emptyBitmap = (w, h, color = 0) => {
|
||||
const bitmap = []
|
||||
for (let y = 0; y < h; y ++) {
|
||||
const scanline = []
|
||||
for (let x = 0; x < w; x ++) {
|
||||
scanline.push(color)
|
||||
scanline.push(color)
|
||||
scanline.push(color)
|
||||
scanline.push(color)
|
||||
}
|
||||
bitmap.push(scanline)
|
||||
}
|
||||
return bitmap
|
||||
}
|
||||
|
||||
export const drawByte = (bitmap, x, y, byte) => {
|
||||
bitmap[y][x] = (byte & 0xc0) >> 6
|
||||
bitmap[y][x + 1] = (byte & 0x30) >> 4
|
||||
bitmap[y][x + 2] = (byte & 0x0c) >> 2
|
||||
bitmap[y][x + 3] = (byte & 0x03)
|
||||
}
|
||||
|
||||
const signedByte = (byte) => {
|
||||
if ((byte & 0x80) != 0) {
|
||||
const complement = (byte ^ 0xff) + 1
|
||||
return -complement
|
||||
} else {
|
||||
return byte
|
||||
}
|
||||
}
|
||||
|
||||
const decodeHowHeld = (byte) => {
|
||||
const heldVal = byte & 0xc0
|
||||
if (heldVal == 0) {
|
||||
return "swing"
|
||||
} else if (heldVal == 0x40) {
|
||||
return "out"
|
||||
} else if (heldVal == 0x80) {
|
||||
return "both"
|
||||
} else {
|
||||
return "at_side"
|
||||
}
|
||||
}
|
||||
|
||||
const encodeHowHeld = (howHeld) => {
|
||||
if (howHeld == "swing") {
|
||||
return 0x00
|
||||
} else if (howHeld == "out") {
|
||||
return 0x40
|
||||
} else if (howHeld == "both") {
|
||||
return 0x80
|
||||
} else if (howHeld == "at_side") {
|
||||
return 0xc0
|
||||
} else {
|
||||
throw new Error(`Unknown hold "${howHeld}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const decodeCelType = (byte) => {
|
||||
const typeVal = byte & 0xc0
|
||||
if (typeVal == 0x00) {
|
||||
if ((byte & 0x20) == 0) {
|
||||
return "bitmap"
|
||||
} else {
|
||||
return "text"
|
||||
}
|
||||
} else if (typeVal == 0x40) {
|
||||
return "trap"
|
||||
} else if (typeVal == 0x80) {
|
||||
return "box"
|
||||
} else {
|
||||
return "circle"
|
||||
}
|
||||
}
|
||||
|
||||
const encodeCelType = (type) => {
|
||||
if (type == "bitmap") {
|
||||
return 0x00
|
||||
} else if (type == "text") {
|
||||
return 0x20
|
||||
} else if (type == "trap") {
|
||||
return 0x40
|
||||
} else if (type == "box") {
|
||||
return 0x80
|
||||
} else if (type == "circle") {
|
||||
return 0xc0
|
||||
} else {
|
||||
throw new Error(`Unknown cel type "${type}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const celDecoder = {}
|
||||
const celEncoder = {}
|
||||
|
||||
celDecoder.bitmap = (data, cel) => {
|
||||
// bitmap cells are RLE-encoded vertical strips of bytes. Decoding starts from the bottom-left
|
||||
// and proceeds upwards until the top of the bitmap is hit; then then next vertical strip is decoded.
|
||||
// Each byte describes four 2-bit pixels.
|
||||
const bitmap = emptyBitmap(cel.width, cel.height)
|
||||
let ibmp = 0
|
||||
const end = cel.width * cel.height
|
||||
const putByte = (byte) => {
|
||||
const x = Math.floor(ibmp / cel.height) * 4
|
||||
const y = (cel.height - (ibmp % cel.height)) - 1
|
||||
drawByte(bitmap, x, y, byte)
|
||||
ibmp ++
|
||||
}
|
||||
let i = 6
|
||||
while (ibmp < end) {
|
||||
const byte = data.getUint8(i)
|
||||
i ++
|
||||
if (byte == 0) {
|
||||
// A zero byte denotes the start of a run of identical bytes. The second
|
||||
// byte denotes the number of repetitions.
|
||||
const count = data.getUint8(i)
|
||||
i ++
|
||||
if ((count & 0x80) == 0) {
|
||||
// if the high bit of the count is not set, we read a third byte to
|
||||
// determine the byte to repeat.
|
||||
const val = data.getUint8(i)
|
||||
i ++
|
||||
for (let repeat = 0; repeat < count; repeat ++) {
|
||||
putByte(val)
|
||||
}
|
||||
} else {
|
||||
// if the high bit of the count is set, the lower 7 bits are used as
|
||||
// the count, and a fully transparent byte is repeated.
|
||||
for (let repeat = 0; repeat < (count & 0x7f); repeat ++) {
|
||||
putByte(0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// non-zero bytes are raw bitmap data
|
||||
putByte(byte)
|
||||
}
|
||||
}
|
||||
cel.bitmap = bitmap
|
||||
}
|
||||
|
||||
celDecoder.box = (data, cel) => {
|
||||
const bitmap = emptyBitmap(cel.width, cel.height)
|
||||
cel.borderLR = (data.getUint8(0) & 0x20) != 0
|
||||
cel.borderTB = (data.getUint8(0) & 0x10) != 0
|
||||
cel.pattern = data.getUint8(6)
|
||||
for (let y = 0; y < cel.height; y ++) {
|
||||
for (let x = 0; x < cel.width; x ++) {
|
||||
if (cel.borderTB && (y == 0 || y == (cel.height - 1))) {
|
||||
drawByte(bitmap, x * 4, y, 0xaa)
|
||||
} else {
|
||||
drawByte(bitmap, x * 4, y, cel.pattern)
|
||||
}
|
||||
}
|
||||
if (cel.borderLR) {
|
||||
const line = bitmap[y]
|
||||
line[0] = 2
|
||||
line[line.length - 1] = 2
|
||||
}
|
||||
}
|
||||
cel.bitmap = bitmap
|
||||
}
|
||||
|
||||
const horizontalLine = (bitmap, xa, xb, y, patternByte) => {
|
||||
const xStart = xa - (xa % 4)
|
||||
const xEnd = (xb + (3 - (xb % 4))) - 3
|
||||
for (let x = xStart + 4; x < xEnd; x += 4) {
|
||||
drawByte(bitmap, x, y, patternByte)
|
||||
}
|
||||
const startBit = ((xa - xStart) * 2)
|
||||
const startByte = (0xff >> startBit) & patternByte
|
||||
drawByte(bitmap, xStart, y, startByte)
|
||||
const endBit = (((xEnd + 3) - xb) * 2)
|
||||
const endByte = (0xff << endBit) & patternByte
|
||||
drawByte(bitmap, xEnd, y, endByte)
|
||||
}
|
||||
|
||||
celDecoder.trap = (data, cel) => {
|
||||
let border = false
|
||||
// trap.m:21 - high-bit set means "draw a border"
|
||||
// It looks like this was used as a flag and the real height
|
||||
// was ORed with 0x80 - see house2.m, sign2.m
|
||||
// There are also trapezoids that use 0x80 as their height -
|
||||
// bwall6.m, bwall7.m, bwall9.m, magic_wall.m
|
||||
// This appears to be special-cased to mean "no border" at trap.m:26
|
||||
// mix.m:253 appears to have the logic to calculate y2, extracting
|
||||
// the height by ANDing with 0x7f (when not 0x80)
|
||||
if ((cel.height & 0x80) != 0 && cel.height != 0x80) {
|
||||
border = true
|
||||
cel.height = cel.height & 0x7f
|
||||
}
|
||||
if ((data.getUint8(0) & 0x10) == 0) {
|
||||
// shape_pattern is a repeating 4-pixel colour, same as box
|
||||
cel.pattern = data.getUint8(6)
|
||||
} else {
|
||||
// shape_pattern is 0xff, and the pattern is a bitmap that follows
|
||||
// the trapezoid definition
|
||||
// dline.m:103 - first two bytes are bitmasks used for efficiently calculating
|
||||
// offsets into the texture. This means that the dimensions will be a power of
|
||||
// two, and we can get the width and height simply by adding one to the mask.
|
||||
const texW = data.getUint8(11) + 1
|
||||
const texH = data.getUint8(12) + 1
|
||||
cel.texture = emptyBitmap(texW, texH)
|
||||
let i = 13
|
||||
// dline.m:111 - the y position into the texture is calculated by
|
||||
// ANDing y1 with the height mask; thus, unlike prop bitmaps, we decode
|
||||
// from the top down
|
||||
for (let y = 0; y < texH; y ++) {
|
||||
for (let x = 0; x < texW; x ++) {
|
||||
drawByte(cel.texture, x * 4, y, data.getUint8(i))
|
||||
i ++
|
||||
}
|
||||
}
|
||||
}
|
||||
cel.x1a = data.getUint8(7)
|
||||
cel.x1b = data.getUint8(8)
|
||||
cel.x2a = data.getUint8(9)
|
||||
cel.x2b = data.getUint8(10)
|
||||
|
||||
// trapezoid-drawing algorithm:
|
||||
// draw_line: draws a line from x1a,y1 to x1b, y1
|
||||
// handles border drawing (last/first line, edges)
|
||||
// decreases vcount, then jumps to cycle1 if there
|
||||
// are more lines
|
||||
// cycle1: run bresenham, determine if x1a (left edge) needs to be incremented
|
||||
// or decremented (self-modifying code! the instruction in inc_dec1 is
|
||||
// written at trap.m:52)
|
||||
// has logic to jump back to cycle1 if we have a sharp enough angle that
|
||||
// we need to move more than one pixel horizontally
|
||||
// cycle2: same thing, but for x2a (right edge)
|
||||
// at the end, increments y1 and jumps back to the top of draw_line
|
||||
cel.width = Math.floor((Math.max(cel.x1a, cel.x1b, cel.x2a, cel.x2b) + 3) / 4)
|
||||
// trap.m:32 - delta_y and vcount are calculated by subtracting y2 - y1.
|
||||
// mix.m:253: y2 is calculated as cel_y + cel_height
|
||||
// mix.m:261: y1 is calculated as cel_y + 1
|
||||
// So for a one-pixel tall trapezoid, deltay is 0, because y1 == y2.
|
||||
// vcount is decremented until it reaches -1, compensating for the off-by-one.
|
||||
const deltay = cel.height - 1
|
||||
cel.bitmap = emptyBitmap(cel.width, cel.height)
|
||||
const dxa = Math.abs(cel.x1a - cel.x2a)
|
||||
const dxb = Math.abs(cel.x1b - cel.x2b)
|
||||
const countMaxA = Math.max(dxa, deltay)
|
||||
const countMaxB = Math.max(dxb, deltay)
|
||||
const inca = cel.x1a < cel.x2a ? 1 : -1
|
||||
const incb = cel.x1b < cel.x2b ? 1 : -1
|
||||
let x1aLo = Math.floor(countMaxA / 2)
|
||||
let y1aLo = x1aLo
|
||||
let x1bLo = Math.floor(countMaxB / 2)
|
||||
let y1bLo = x1bLo
|
||||
let xa = cel.x1a
|
||||
let xb = cel.x1b
|
||||
for (let y = 0; y < cel.height; y ++) {
|
||||
const line = cel.bitmap[y]
|
||||
if (border && (y == 0 || y == (cel.height - 1))) {
|
||||
// top and bottom border line
|
||||
horizontalLine(cel.bitmap, xa, xb, y, 0xaa, true)
|
||||
} else {
|
||||
if (cel.texture) {
|
||||
const texLine = cel.texture[y % cel.texture.length]
|
||||
for (let x = xa; x <= xb; x ++) {
|
||||
line[x] = texLine[x % texLine.length]
|
||||
}
|
||||
} else {
|
||||
horizontalLine(cel.bitmap, xa, xb, y, cel.pattern, border)
|
||||
}
|
||||
}
|
||||
|
||||
if (border) {
|
||||
line[xa] = 2
|
||||
line[xb] = 2
|
||||
}
|
||||
|
||||
// cycle1: move xa
|
||||
do {
|
||||
x1aLo += dxa
|
||||
if (x1aLo >= countMaxA) {
|
||||
x1aLo -= countMaxA
|
||||
xa += inca
|
||||
}
|
||||
y1aLo += deltay
|
||||
} while (y1aLo < countMaxA)
|
||||
y1aLo -= countMaxA
|
||||
|
||||
// cycle2: move xb
|
||||
do {
|
||||
x1bLo += dxb
|
||||
if (x1bLo >= countMaxB) {
|
||||
x1bLo -= countMaxB
|
||||
xb += incb
|
||||
}
|
||||
y1bLo += deltay
|
||||
} while (y1bLo < countMaxA)
|
||||
y1bLo -= countMaxA
|
||||
}
|
||||
}
|
||||
|
||||
const decodeCel = (data, changesColorRam) => {
|
||||
const cel = {
|
||||
data: data,
|
||||
changesColorRam: changesColorRam,
|
||||
type: decodeCelType(data.getUint8(0)),
|
||||
// wild: (data.getUint8(0) & 0x10) == 0 ? "color" : "pattern",
|
||||
width: data.getUint8(0) & 0x0f,
|
||||
height: data.getUint8(1),
|
||||
xOffset: data.getInt8(2),
|
||||
yOffset: data.getInt8(3),
|
||||
xRel: data.getInt8(4),
|
||||
yRel: data.getInt8(5)
|
||||
}
|
||||
if (celDecoder[cel.type]) {
|
||||
celDecoder[cel.type](data, cel)
|
||||
}
|
||||
return cel
|
||||
}
|
||||
|
||||
const decodeSide = (byte) => {
|
||||
const side = byte & 0x03
|
||||
if (side == 0x00) {
|
||||
return "left"
|
||||
} else if (side == 0x01) {
|
||||
return "right"
|
||||
} else if (side == 0x02) {
|
||||
return "up"
|
||||
} else {
|
||||
return "down"
|
||||
}
|
||||
}
|
||||
const encodeSide = (side) => {
|
||||
if (side == "left") {
|
||||
return 0x00
|
||||
} else if (side == "right") {
|
||||
return 0x01
|
||||
} else if (side == "up") {
|
||||
return 0x02
|
||||
} else if (side == "down") {
|
||||
return 0x03
|
||||
} else {
|
||||
throw new Error(`Unknown side "${side}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const decodeWalkto = (byte) => {
|
||||
return { fromSide: decodeSide(byte), offset: signedByte(byte & 0xfc) }
|
||||
}
|
||||
|
||||
const encodeWalkto = ({ fromSide, offset }) => {
|
||||
return encodeSide(fromSide) | (offset & 0xfc)
|
||||
}
|
||||
|
||||
const decodeAnimations = (data, startEndTableOff, firstCelOff, stateCount) => {
|
||||
const animations = []
|
||||
// The prop structure also does not encode a count for how many frames there are, so we simply
|
||||
// stop parsing once we find one that doesn't make sense.
|
||||
// We also use the heuristic that this structure always precedes the first cel, as that seems to be
|
||||
// consistently be the case with all the props in the Habitat source tree. We'll stop reading
|
||||
// animation data if we cross that boundary. If we encounter a prop that has the animation data
|
||||
// _after_ the cel data, which would be legal but doesn't happen in practice, then we ignore this
|
||||
// heuristic rather than failing to parse any animation data.
|
||||
// It's possible for there to be no frames, which is represented by an offset of 0 (no_animation)
|
||||
if (startEndTableOff != 0) {
|
||||
for (let frameOff = startEndTableOff; (startEndTableOff > firstCelOff) || (frameOff < firstCelOff); frameOff += 2) {
|
||||
// each animation is two bytes: the starting state, and the ending state
|
||||
// the first byte can have its high bit set to indicate that the animation should cycle
|
||||
const cycle = (data.getUint8(frameOff) & 0x80) != 0
|
||||
const startState = data.getUint8(frameOff) & 0x7f
|
||||
const endState = data.getUint8(frameOff + 1)
|
||||
if (startState >= stateCount || endState >= stateCount) {
|
||||
break
|
||||
}
|
||||
animations.push({ cycle: cycle, startState: startState, endState: endState })
|
||||
}
|
||||
}
|
||||
return animations
|
||||
}
|
||||
|
||||
export const decodeProp = (data) => {
|
||||
const prop = {
|
||||
data: data,
|
||||
howHeld: decodeHowHeld(data.getUint8(0)),
|
||||
colorBitmask: data.getUint8(1),
|
||||
containerXYOff: data.getUint8(3), // TODO: parse this when nonzero
|
||||
walkto: { left: decodeWalkto(data.getUint8(4)), right: decodeWalkto(data.getUint8(5)), yoff: data.getInt8(6) },
|
||||
celmasks: [],
|
||||
cels: []
|
||||
}
|
||||
const stateCount = (data.getUint8(0) & 0x3f) + 1
|
||||
const graphicStateOff = data.getUint8(2)
|
||||
const celMasksOff = 7
|
||||
const celOffsetsOff = celMasksOff + stateCount
|
||||
|
||||
// The prop structure does not directly encode a count for how many cels there are, but each
|
||||
// "graphic state" is defined by a bitmask marking which cels are present, and we do know how
|
||||
// many states there are. We can assume that all cels are referenced by at least one state,
|
||||
// and use that to determine the cel count.
|
||||
let allCelsMask = 0
|
||||
for (let icelmask = 0; icelmask < stateCount; icelmask ++) {
|
||||
const celmask = data.getUint8(celMasksOff + icelmask)
|
||||
prop.celmasks.push(celmask)
|
||||
allCelsMask |= celmask
|
||||
}
|
||||
if (allCelsMask != 0x80 && allCelsMask != 0xc0 && allCelsMask != 0xe0 && allCelsMask != 0xf0 &&
|
||||
allCelsMask != 0xf8 && allCelsMask != 0xfc && allCelsMask != 0xfe && allCelsMask != 0xff) {
|
||||
throw new Error("Inconsistent graphic state cel masks - implies unused cel data")
|
||||
}
|
||||
let firstCelOff = Number.POSITIVE_INFINITY
|
||||
for (let celOffsetOff = celOffsetsOff; allCelsMask != 0; celOffsetOff += 2) {
|
||||
const icel = prop.cels.length
|
||||
const celbit = 0x80 >> icel
|
||||
const celOff = data.getUint16(celOffsetOff, LE)
|
||||
firstCelOff = Math.min(celOff, firstCelOff)
|
||||
prop.cels.push(decodeCel(new DataView(data.buffer, celOff), (prop.colorBitmask & celbit) != 0))
|
||||
allCelsMask = (allCelsMask << 1) & 0xff
|
||||
}
|
||||
prop.animations = decodeAnimations(data, graphicStateOff, firstCelOff, stateCount)
|
||||
return prop
|
||||
}
|
||||
|
||||
const decodeLimb = (data, limb) => {
|
||||
let frameCount = data.getUint8(0) + 1
|
||||
limb.frames = []
|
||||
for (let iframe = 0; iframe < frameCount; iframe ++) {
|
||||
limb.frames.push(data.getInt8(3 + iframe))
|
||||
}
|
||||
const celOffsetsOff = 3 + frameCount
|
||||
const maxCelIndex = Math.max(...limb.frames)
|
||||
limb.cels = []
|
||||
let firstCelOff
|
||||
for (let icel = 0; icel <= maxCelIndex; icel ++) {
|
||||
const celOff = data.getUint16(celOffsetsOff + (icel * 2), LE)
|
||||
if (icel == 0) {
|
||||
firstCelOff = celOff
|
||||
}
|
||||
limb.cels.push(decodeCel(new DataView(data.buffer, data.byteOffset + celOff)))
|
||||
}
|
||||
limb.animations = decodeAnimations(data, data.getUint8(2), firstCelOff, limb.frames.length)
|
||||
}
|
||||
|
||||
export const choreographyActions = [
|
||||
"init", "stand", "walk", "hand_back", "sit_floor", "sit_chair", "bend_over",
|
||||
"bend_back", "point", "throw", "get_shot", "jump", "punch", "wave",
|
||||
"frown", "stand_back", "walk_front", "walk_back", "stand_front",
|
||||
"unpocket", "gimme", "knife", "arm_get", "hand_out", "operate",
|
||||
"arm_back", "shoot1", "shoot2", "nop", "sit_front"
|
||||
]
|
||||
|
||||
export const decodeBody = (data) => {
|
||||
const body = {
|
||||
data: data,
|
||||
headCelNumber: data.getUint8(19),
|
||||
frozenWhenStands: data.getUint8(20),
|
||||
frontFacingLimbOrder: [],
|
||||
backFacingLimbOrder: [],
|
||||
limbs: [],
|
||||
choreography: [],
|
||||
actions: {}
|
||||
}
|
||||
for (let ilimb = 0; ilimb < 6; ilimb ++) {
|
||||
body.frontFacingLimbOrder.push(data.getUint8(27 + ilimb))
|
||||
body.backFacingLimbOrder.push(data.getUint8(33 + ilimb))
|
||||
const limb = {
|
||||
pattern: data.getUint8(21 + ilimb),
|
||||
affectedByHeight: data.getUint8(39 + ilimb)
|
||||
}
|
||||
const limbOff = data.getUint16(7 + (ilimb * 2), LE)
|
||||
decodeLimb(new DataView(data.buffer, limbOff), limb)
|
||||
body.limbs.push(limb)
|
||||
}
|
||||
const choreographyIndexOff = data.getUint16(0, LE)
|
||||
const choreographyTableOff = data.getUint16(2, LE)
|
||||
const indexToChoreography = new Map()
|
||||
for (const [i, action] of choreographyActions.entries()) {
|
||||
let tableIndex = data.getUint8(choreographyIndexOff + i)
|
||||
let choreographyIndex = indexToChoreography.get(tableIndex)
|
||||
if (choreographyIndex == undefined) {
|
||||
choreographyIndex = body.choreography.length
|
||||
indexToChoreography.set(tableIndex, choreographyIndex)
|
||||
const choreography = []
|
||||
body.choreography.push(choreography)
|
||||
for (;; tableIndex ++) {
|
||||
const state = data.getUint8(choreographyTableOff + tableIndex)
|
||||
let limb = (state & 0x70) >> 4
|
||||
let animation = state & 0x0f
|
||||
if (limb == 6) {
|
||||
limb = 5
|
||||
animation += 0x10
|
||||
}
|
||||
choreography.push({ limb, animation })
|
||||
if ((state & 0x80) != 0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
body.actions[action] = choreographyIndex
|
||||
}
|
||||
return body
|
||||
}
|
17
detail.html
17
detail.html
|
@ -15,7 +15,6 @@
|
|||
line-height:1.2
|
||||
}
|
||||
</style>
|
||||
<script src="index.js?v=4"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="filename"></h1>
|
||||
|
@ -33,7 +32,10 @@
|
|||
</div>
|
||||
<div id="errors"></div>
|
||||
<a href="index.html">Back</a>
|
||||
<script>
|
||||
<script type="module">
|
||||
import { decodeProp } from "./codec.js"
|
||||
import { docBuilder, decodeBinary, showAll, textNode, propAnimationShower, celmaskShower, celShower } from "./show.js"
|
||||
|
||||
const propFilter = (key, value) => {
|
||||
if (key != "bitmap" && key != "data" && key != "canvas") {
|
||||
return value
|
||||
|
@ -47,15 +49,16 @@
|
|||
const q = new URLSearchParams(window.location.search)
|
||||
const filename = q.get("f")
|
||||
document.getElementById("filename").innerText = filename
|
||||
const doc = docBuilder({ errorContainer: document.getElementById("errors") })
|
||||
try {
|
||||
const prop = await decodeBinary(filename, PropImpl)
|
||||
const prop = await decodeBinary(filename, decodeProp)
|
||||
dumpProp(prop, document.getElementById("data"))
|
||||
if (prop.error) {
|
||||
showError(prop.error, filename)
|
||||
doc.showError(prop.error, filename)
|
||||
} else {
|
||||
showAnimations(prop, document.getElementById("animations"), PropImpl)
|
||||
showStates(prop, document.getElementById("states"))
|
||||
showCels(prop, document.getElementById("cels"))
|
||||
showAll(doc, document.getElementById("animations"), filename, prop.animations, propAnimationShower(prop))
|
||||
showAll(doc, document.getElementById("states"), filename, prop.celmasks, celmaskShower(prop))
|
||||
showAll(doc, document.getElementById("cels"), filename, prop.cels, celShower())
|
||||
}
|
||||
} catch (e) {
|
||||
showError(e, filename)
|
||||
|
|
19
index.html
19
index.html
|
@ -15,18 +15,19 @@
|
|||
line-height:1.2
|
||||
}
|
||||
</style>
|
||||
<script src="index.js?v=4"></script>
|
||||
<script>
|
||||
function showErrors() {
|
||||
<script type="module">
|
||||
import { displayBodies, displayProps } from "./index.js"
|
||||
|
||||
window.showErrors = () => {
|
||||
document.getElementById('errors').style.display = 'block'
|
||||
}
|
||||
|
||||
const displayEverything = async () => {
|
||||
await displayList("bodies.json", "bodies", BodyImpl)
|
||||
await displayList("heads.json", "heads", PropImpl)
|
||||
await displayList("props.json", "props", PropImpl)
|
||||
await displayList("misc.json", "misc", PropImpl)
|
||||
await displayList("beta.json", "beta", PropImpl)
|
||||
const displayEverything = () => {
|
||||
displayBodies("bodies.json", "bodies")
|
||||
displayProps("heads.json", "heads")
|
||||
displayProps("props.json", "props")
|
||||
displayProps("misc.json", "misc")
|
||||
displayProps("beta.json", "beta")
|
||||
}
|
||||
|
||||
displayEverything()
|
||||
|
|
903
index.js
903
index.js
|
@ -1,893 +1,34 @@
|
|||
const LE = true // little-endian
|
||||
import { decodeProp, decodeBody } from "./codec.js"
|
||||
import { docBuilder, showAll, decodeBinary, textNode, propAnimationShower, celmaskShower, actionShower } from "./show.js"
|
||||
|
||||
const readBinary = async (url) => {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
console.log(response)
|
||||
throw Error(`Failed to download ${url}`)
|
||||
}
|
||||
return new DataView(await response.arrayBuffer())
|
||||
}
|
||||
|
||||
const makeCanvas = (w, h) => {
|
||||
const canvas = document.createElement("canvas")
|
||||
canvas.width = w
|
||||
canvas.height = h
|
||||
return canvas
|
||||
}
|
||||
|
||||
// C64 RGB values taken from https://www.c64-wiki.com/wiki/Color
|
||||
const c64Colors = [
|
||||
0x000000, 0xffffff, 0x880000, 0xaaffee, 0xcc44cc, 0x00cc55,
|
||||
0x0000aa, 0xeeee77, 0xdd8855, 0x664400, 0xff7777, 0x333333,
|
||||
0x777777, 0xaaff66, 0x0088ff, 0xbbbbbb
|
||||
]
|
||||
|
||||
// from paint.m:447
|
||||
const celPatterns = [
|
||||
[0x00, 0x00, 0x00, 0x00],
|
||||
[0xaa, 0xaa, 0xaa, 0xaa],
|
||||
[0xff, 0xff, 0xff, 0xff],
|
||||
[0xe2, 0xe2, 0xe2, 0xe2],
|
||||
[0x8b, 0xbe, 0x0f, 0xcc],
|
||||
[0xee, 0x00, 0xee, 0x00],
|
||||
[0xf0, 0xf0, 0x0f, 0x0f],
|
||||
[0x22, 0x88, 0x22, 0x88],
|
||||
[0x32, 0x88, 0x23, 0x88],
|
||||
[0x00, 0x28, 0x3b, 0x0c],
|
||||
[0x33, 0xcc, 0x33, 0xcc],
|
||||
[0x08, 0x80, 0x0c, 0x80],
|
||||
[0x3f, 0x3f, 0xf3, 0xf3],
|
||||
[0xaa, 0x3f, 0xaa, 0xf3],
|
||||
[0xaa, 0x00, 0xaa, 0x00],
|
||||
[0x55, 0x55, 0x55, 0x55]
|
||||
]
|
||||
|
||||
const defaultColors = {
|
||||
wildcard: 6,
|
||||
skin: 10,
|
||||
pattern: 15
|
||||
}
|
||||
|
||||
const canvasFromBitmap = (bitmap, colors = {}) => {
|
||||
if (bitmap.length == 0 || bitmap[0].length == 0) {
|
||||
return null
|
||||
}
|
||||
const { wildcard, pattern, skin } = { ...defaultColors, ...colors }
|
||||
const patternColors = [6, wildcard, 0, skin]
|
||||
const h = bitmap.length
|
||||
const w = bitmap[0].length * 2
|
||||
const canvas = makeCanvas(w, h)
|
||||
const ctx = canvas.getContext("2d")
|
||||
const img = ctx.createImageData(w, h)
|
||||
|
||||
const putpixel = (x, y, r, g, b, a) => {
|
||||
const i = (x * 8) + (y * w * 4)
|
||||
img.data[i] = r
|
||||
img.data[i + 1] = g
|
||||
img.data[i + 2] = b
|
||||
img.data[i + 3] = a
|
||||
img.data[i + 4] = r
|
||||
img.data[i + 5] = g
|
||||
img.data[i + 6] = b
|
||||
img.data[i + 7] = a
|
||||
}
|
||||
|
||||
for (let y = 0; y < bitmap.length; y ++) {
|
||||
const line = bitmap[y]
|
||||
const patbyte = celPatterns[pattern][y % 4]
|
||||
for (let x = 0; x < line.length; x ++) {
|
||||
const pixel = line[x]
|
||||
let color = null
|
||||
if (pixel == 0) { // transparent
|
||||
putpixel(x, y, 0, 0, 0, 0)
|
||||
} else if (pixel == 1) { // wild
|
||||
const shift = (x % 4) * 2
|
||||
color = patternColors[(patbyte & (0xc0 >> shift)) >> (6 - shift)]
|
||||
} else {
|
||||
color = patternColors[pixel]
|
||||
}
|
||||
if (color != null) {
|
||||
const rgb = c64Colors[color]
|
||||
putpixel(x, y, (rgb & 0xff0000) >> 16, (rgb & 0xff00) >> 8, rgb & 0xff, 0xff)
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.putImageData(img, 0, 0)
|
||||
return canvas
|
||||
}
|
||||
|
||||
const signedByte = (byte) => {
|
||||
if ((byte & 0x80) != 0) {
|
||||
const complement = (byte ^ 0xff) + 1
|
||||
return -complement
|
||||
const showProp = (prop) => {
|
||||
if (prop.filename == 'heads/fhead.bin') {
|
||||
return textNode("CW: Pixel genitals")
|
||||
} else if (prop.animations.length > 0) {
|
||||
return prop.animations.map(propAnimationShower(prop))
|
||||
} else {
|
||||
return byte
|
||||
return prop.celmasks.map(celmaskShower(prop))
|
||||
}
|
||||
}
|
||||
|
||||
// JS bitmap format: array of scanlines, each scanline being an array of numbers from 0-3
|
||||
const emptyBitmap = (w, h, color = 0) => {
|
||||
const bitmap = []
|
||||
for (let y = 0; y < h; y ++) {
|
||||
const scanline = []
|
||||
for (let x = 0; x < w; x ++) {
|
||||
scanline.push(color)
|
||||
scanline.push(color)
|
||||
scanline.push(color)
|
||||
scanline.push(color)
|
||||
}
|
||||
bitmap.push(scanline)
|
||||
}
|
||||
return bitmap
|
||||
}
|
||||
const showBody = (body) => actionShower(body)("walk")
|
||||
|
||||
const drawByte = (bitmap, x, y, byte) => {
|
||||
bitmap[y][x] = (byte & 0xc0) >> 6
|
||||
bitmap[y][x + 1] = (byte & 0x30) >> 4
|
||||
bitmap[y][x + 2] = (byte & 0x0c) >> 2
|
||||
bitmap[y][x + 3] = (byte & 0x03)
|
||||
}
|
||||
|
||||
// Prop decoding functions
|
||||
const decodeHowHeld = (byte) => {
|
||||
const heldVal = byte & 0xc0
|
||||
if (heldVal == 0) {
|
||||
return "swing"
|
||||
} else if (heldVal == 0x40) {
|
||||
return "out"
|
||||
} else if (heldVal == 0x80) {
|
||||
return "both"
|
||||
} else {
|
||||
return "at_side"
|
||||
}
|
||||
}
|
||||
|
||||
const encodeHowHeld = (howHeld) => {
|
||||
if (howHeld == "swing") {
|
||||
return 0x00
|
||||
} else if (howHeld == "out") {
|
||||
return 0x40
|
||||
} else if (howHeld == "both") {
|
||||
return 0x80
|
||||
} else if (howHeld == "at_side") {
|
||||
return 0xc0
|
||||
} else {
|
||||
throw new Error(`Unknown hold "${howHeld}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const decodeCelType = (byte) => {
|
||||
const typeVal = byte & 0xc0
|
||||
if (typeVal == 0x00) {
|
||||
if ((byte & 0x20) == 0) {
|
||||
return "bitmap"
|
||||
} else {
|
||||
return "text"
|
||||
}
|
||||
} else if (typeVal == 0x40) {
|
||||
return "trap"
|
||||
} else if (typeVal == 0x80) {
|
||||
return "box"
|
||||
} else {
|
||||
return "circle"
|
||||
}
|
||||
}
|
||||
|
||||
const encodeCelType = (type) => {
|
||||
if (type == "bitmap") {
|
||||
return 0x00
|
||||
} else if (type == "text") {
|
||||
return 0x20
|
||||
} else if (type == "trap") {
|
||||
return 0x40
|
||||
} else if (type == "box") {
|
||||
return 0x80
|
||||
} else if (type == "circle") {
|
||||
return 0xc0
|
||||
} else {
|
||||
throw new Error(`Unknown cel type "${type}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const celDecoder = {}
|
||||
const celEncoder = {}
|
||||
|
||||
celDecoder.bitmap = (data, cel) => {
|
||||
// bitmap cells are RLE-encoded vertical strips of bytes. Decoding starts from the bottom-left
|
||||
// and proceeds upwards until the top of the bitmap is hit; then then next vertical strip is decoded.
|
||||
// Each byte describes four 2-bit pixels.
|
||||
const bitmap = emptyBitmap(cel.width, cel.height)
|
||||
let ibmp = 0
|
||||
const end = cel.width * cel.height
|
||||
const putByte = (byte) => {
|
||||
const x = Math.floor(ibmp / cel.height) * 4
|
||||
const y = (cel.height - (ibmp % cel.height)) - 1
|
||||
drawByte(bitmap, x, y, byte)
|
||||
ibmp ++
|
||||
}
|
||||
let i = 6
|
||||
while (ibmp < end) {
|
||||
const byte = data.getUint8(i)
|
||||
i ++
|
||||
if (byte == 0) {
|
||||
// A zero byte denotes the start of a run of identical bytes. The second
|
||||
// byte denotes the number of repetitions.
|
||||
const count = data.getUint8(i)
|
||||
i ++
|
||||
if ((count & 0x80) == 0) {
|
||||
// if the high bit of the count is not set, we read a third byte to
|
||||
// determine the byte to repeat.
|
||||
const val = data.getUint8(i)
|
||||
i ++
|
||||
for (let repeat = 0; repeat < count; repeat ++) {
|
||||
putByte(val)
|
||||
}
|
||||
} else {
|
||||
// if the high bit of the count is set, the lower 7 bits are used as
|
||||
// the count, and a fully transparent byte is repeated.
|
||||
for (let repeat = 0; repeat < (count & 0x7f); repeat ++) {
|
||||
putByte(0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// non-zero bytes are raw bitmap data
|
||||
putByte(byte)
|
||||
}
|
||||
}
|
||||
cel.bitmap = bitmap
|
||||
}
|
||||
|
||||
celDecoder.box = (data, cel) => {
|
||||
const bitmap = emptyBitmap(cel.width, cel.height)
|
||||
cel.borderLR = (data.getUint8(0) & 0x20) != 0
|
||||
cel.borderTB = (data.getUint8(0) & 0x10) != 0
|
||||
cel.pattern = data.getUint8(6)
|
||||
for (let y = 0; y < cel.height; y ++) {
|
||||
for (let x = 0; x < cel.width; x ++) {
|
||||
if (cel.borderTB && (y == 0 || y == (cel.height - 1))) {
|
||||
drawByte(bitmap, x * 4, y, 0xaa)
|
||||
} else {
|
||||
drawByte(bitmap, x * 4, y, cel.pattern)
|
||||
}
|
||||
}
|
||||
if (cel.borderLR) {
|
||||
const line = bitmap[y]
|
||||
line[0] = 2
|
||||
line[line.length - 1] = 2
|
||||
}
|
||||
}
|
||||
cel.bitmap = bitmap
|
||||
}
|
||||
|
||||
const horizontalLine = (bitmap, xa, xb, y, patternByte) => {
|
||||
const xStart = xa - (xa % 4)
|
||||
const xEnd = (xb + (3 - (xb % 4))) - 3
|
||||
for (let x = xStart + 4; x < xEnd; x += 4) {
|
||||
drawByte(bitmap, x, y, patternByte)
|
||||
}
|
||||
const startBit = ((xa - xStart) * 2)
|
||||
const startByte = (0xff >> startBit) & patternByte
|
||||
drawByte(bitmap, xStart, y, startByte)
|
||||
const endBit = (((xEnd + 3) - xb) * 2)
|
||||
const endByte = (0xff << endBit) & patternByte
|
||||
drawByte(bitmap, xEnd, y, endByte)
|
||||
}
|
||||
|
||||
celDecoder.trap = (data, cel) => {
|
||||
let border = false
|
||||
// trap.m:21 - high-bit set means "draw a border"
|
||||
// It looks like this was used as a flag and the real height
|
||||
// was ORed with 0x80 - see house2.m, sign2.m
|
||||
// There are also trapezoids that use 0x80 as their height -
|
||||
// bwall6.m, bwall7.m, bwall9.m, magic_wall.m
|
||||
// This appears to be special-cased to mean "no border" at trap.m:26
|
||||
// mix.m:253 appears to have the logic to calculate y2, extracting
|
||||
// the height by ANDing with 0x7f (when not 0x80)
|
||||
if ((cel.height & 0x80) != 0 && cel.height != 0x80) {
|
||||
border = true
|
||||
cel.height = cel.height & 0x7f
|
||||
}
|
||||
if ((data.getUint8(0) & 0x10) == 0) {
|
||||
// shape_pattern is a repeating 4-pixel colour, same as box
|
||||
cel.pattern = data.getUint8(6)
|
||||
} else {
|
||||
// shape_pattern is 0xff, and the pattern is a bitmap that follows
|
||||
// the trapezoid definition
|
||||
// dline.m:103 - first two bytes are bitmasks used for efficiently calculating
|
||||
// offsets into the texture. This means that the dimensions will be a power of
|
||||
// two, and we can get the width and height simply by adding one to the mask.
|
||||
const texW = data.getUint8(11) + 1
|
||||
const texH = data.getUint8(12) + 1
|
||||
cel.texture = emptyBitmap(texW, texH)
|
||||
let i = 13
|
||||
// dline.m:111 - the y position into the texture is calculated by
|
||||
// ANDing y1 with the height mask; thus, unlike prop bitmaps, we decode
|
||||
// from the top down
|
||||
for (let y = 0; y < texH; y ++) {
|
||||
for (let x = 0; x < texW; x ++) {
|
||||
drawByte(cel.texture, x * 4, y, data.getUint8(i))
|
||||
i ++
|
||||
}
|
||||
}
|
||||
}
|
||||
cel.x1a = data.getUint8(7)
|
||||
cel.x1b = data.getUint8(8)
|
||||
cel.x2a = data.getUint8(9)
|
||||
cel.x2b = data.getUint8(10)
|
||||
|
||||
// trapezoid-drawing algorithm:
|
||||
// draw_line: draws a line from x1a,y1 to x1b, y1
|
||||
// handles border drawing (last/first line, edges)
|
||||
// decreases vcount, then jumps to cycle1 if there
|
||||
// are more lines
|
||||
// cycle1: run bresenham, determine if x1a (left edge) needs to be incremented
|
||||
// or decremented (self-modifying code! the instruction in inc_dec1 is
|
||||
// written at trap.m:52)
|
||||
// has logic to jump back to cycle1 if we have a sharp enough angle that
|
||||
// we need to move more than one pixel horizontally
|
||||
// cycle2: same thing, but for x2a (right edge)
|
||||
// at the end, increments y1 and jumps back to the top of draw_line
|
||||
cel.width = Math.floor((Math.max(cel.x1a, cel.x1b, cel.x2a, cel.x2b) + 3) / 4)
|
||||
// trap.m:32 - delta_y and vcount are calculated by subtracting y2 - y1.
|
||||
// mix.m:253: y2 is calculated as cel_y + cel_height
|
||||
// mix.m:261: y1 is calculated as cel_y + 1
|
||||
// So for a one-pixel tall trapezoid, deltay is 0, because y1 == y2.
|
||||
// vcount is decremented until it reaches -1, compensating for the off-by-one.
|
||||
const deltay = cel.height - 1
|
||||
cel.bitmap = emptyBitmap(cel.width, cel.height)
|
||||
const dxa = Math.abs(cel.x1a - cel.x2a)
|
||||
const dxb = Math.abs(cel.x1b - cel.x2b)
|
||||
const countMaxA = Math.max(dxa, deltay)
|
||||
const countMaxB = Math.max(dxb, deltay)
|
||||
const inca = cel.x1a < cel.x2a ? 1 : -1
|
||||
const incb = cel.x1b < cel.x2b ? 1 : -1
|
||||
let x1aLo = Math.floor(countMaxA / 2)
|
||||
let y1aLo = x1aLo
|
||||
let x1bLo = Math.floor(countMaxB / 2)
|
||||
let y1bLo = x1bLo
|
||||
let xa = cel.x1a
|
||||
let xb = cel.x1b
|
||||
for (let y = 0; y < cel.height; y ++) {
|
||||
const line = cel.bitmap[y]
|
||||
if (border && (y == 0 || y == (cel.height - 1))) {
|
||||
// top and bottom border line
|
||||
horizontalLine(cel.bitmap, xa, xb, y, 0xaa, true)
|
||||
} else {
|
||||
if (cel.texture) {
|
||||
const texLine = cel.texture[y % cel.texture.length]
|
||||
for (let x = xa; x <= xb; x ++) {
|
||||
line[x] = texLine[x % texLine.length]
|
||||
}
|
||||
} else {
|
||||
horizontalLine(cel.bitmap, xa, xb, y, cel.pattern, border)
|
||||
}
|
||||
}
|
||||
|
||||
if (border) {
|
||||
line[xa] = 2
|
||||
line[xb] = 2
|
||||
}
|
||||
|
||||
// cycle1: move xa
|
||||
do {
|
||||
x1aLo += dxa
|
||||
if (x1aLo >= countMaxA) {
|
||||
x1aLo -= countMaxA
|
||||
xa += inca
|
||||
}
|
||||
y1aLo += deltay
|
||||
} while (y1aLo < countMaxA)
|
||||
y1aLo -= countMaxA
|
||||
|
||||
// cycle2: move xb
|
||||
do {
|
||||
x1bLo += dxb
|
||||
if (x1bLo >= countMaxB) {
|
||||
x1bLo -= countMaxB
|
||||
xb += incb
|
||||
}
|
||||
y1bLo += deltay
|
||||
} while (y1bLo < countMaxA)
|
||||
y1bLo -= countMaxA
|
||||
}
|
||||
}
|
||||
|
||||
const decodeCel = (data, changesColorRam) => {
|
||||
const cel = {
|
||||
data: data,
|
||||
changesColorRam: changesColorRam,
|
||||
type: decodeCelType(data.getUint8(0)),
|
||||
// wild: (data.getUint8(0) & 0x10) == 0 ? "color" : "pattern",
|
||||
width: data.getUint8(0) & 0x0f,
|
||||
height: data.getUint8(1),
|
||||
xOffset: data.getInt8(2),
|
||||
yOffset: data.getInt8(3),
|
||||
xRel: data.getInt8(4),
|
||||
yRel: data.getInt8(5)
|
||||
}
|
||||
if (celDecoder[cel.type]) {
|
||||
celDecoder[cel.type](data, cel)
|
||||
}
|
||||
return cel
|
||||
}
|
||||
|
||||
const decodeSide = (byte) => {
|
||||
const side = byte & 0x03
|
||||
if (side == 0x00) {
|
||||
return "left"
|
||||
} else if (side == 0x01) {
|
||||
return "right"
|
||||
} else if (side == 0x02) {
|
||||
return "up"
|
||||
} else {
|
||||
return "down"
|
||||
}
|
||||
}
|
||||
const encodeSide = (side) => {
|
||||
if (side == "left") {
|
||||
return 0x00
|
||||
} else if (side == "right") {
|
||||
return 0x01
|
||||
} else if (side == "up") {
|
||||
return 0x02
|
||||
} else if (side == "down") {
|
||||
return 0x03
|
||||
} else {
|
||||
throw new Error(`Unknown side "${side}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const decodeWalkto = (byte) => {
|
||||
return { fromSide: decodeSide(byte), offset: signedByte(byte & 0xfc) }
|
||||
}
|
||||
|
||||
const encodeWalkto = ({ fromSide, offset }) => {
|
||||
return encodeSide(fromSide) | (offset & 0xfc)
|
||||
}
|
||||
|
||||
const decodeAnimations = (data, startEndTableOff, firstCelOff, stateCount) => {
|
||||
const animations = []
|
||||
// The prop structure also does not encode a count for how many frames there are, so we simply
|
||||
// stop parsing once we find one that doesn't make sense.
|
||||
// We also use the heuristic that this structure always precedes the first cel, as that seems to be
|
||||
// consistently be the case with all the props in the Habitat source tree. We'll stop reading
|
||||
// animation data if we cross that boundary. If we encounter a prop that has the animation data
|
||||
// _after_ the cel data, which would be legal but doesn't happen in practice, then we ignore this
|
||||
// heuristic rather than failing to parse any animation data.
|
||||
// It's possible for there to be no frames, which is represented by an offset of 0 (no_animation)
|
||||
if (startEndTableOff != 0) {
|
||||
for (let frameOff = startEndTableOff; (startEndTableOff > firstCelOff) || (frameOff < firstCelOff); frameOff += 2) {
|
||||
// each animation is two bytes: the starting state, and the ending state
|
||||
// the first byte can have its high bit set to indicate that the animation should cycle
|
||||
const cycle = (data.getUint8(frameOff) & 0x80) != 0
|
||||
const startState = data.getUint8(frameOff) & 0x7f
|
||||
const endState = data.getUint8(frameOff + 1)
|
||||
if (startState >= stateCount || endState >= stateCount) {
|
||||
break
|
||||
}
|
||||
animations.push({ cycle: cycle, startState: startState, endState: endState })
|
||||
}
|
||||
}
|
||||
return animations
|
||||
}
|
||||
|
||||
const decodeProp = (data) => {
|
||||
const prop = {
|
||||
data: data,
|
||||
howHeld: decodeHowHeld(data.getUint8(0)),
|
||||
colorBitmask: data.getUint8(1),
|
||||
containerXYOff: data.getUint8(3), // TODO: parse this when nonzero
|
||||
walkto: { left: decodeWalkto(data.getUint8(4)), right: decodeWalkto(data.getUint8(5)), yoff: data.getInt8(6) },
|
||||
celmasks: [],
|
||||
cels: []
|
||||
}
|
||||
const stateCount = (data.getUint8(0) & 0x3f) + 1
|
||||
const graphicStateOff = data.getUint8(2)
|
||||
const celMasksOff = 7
|
||||
const celOffsetsOff = celMasksOff + stateCount
|
||||
|
||||
// The prop structure does not directly encode a count for how many cels there are, but each
|
||||
// "graphic state" is defined by a bitmask marking which cels are present, and we do know how
|
||||
// many states there are. We can assume that all cels are referenced by at least one state,
|
||||
// and use that to determine the cel count.
|
||||
let allCelsMask = 0
|
||||
for (let icelmask = 0; icelmask < stateCount; icelmask ++) {
|
||||
const celmask = data.getUint8(celMasksOff + icelmask)
|
||||
prop.celmasks.push(celmask)
|
||||
allCelsMask |= celmask
|
||||
}
|
||||
if (allCelsMask != 0x80 && allCelsMask != 0xc0 && allCelsMask != 0xe0 && allCelsMask != 0xf0 &&
|
||||
allCelsMask != 0xf8 && allCelsMask != 0xfc && allCelsMask != 0xfe && allCelsMask != 0xff) {
|
||||
throw new Error("Inconsistent graphic state cel masks - implies unused cel data")
|
||||
}
|
||||
let firstCelOff = Number.POSITIVE_INFINITY
|
||||
for (let celOffsetOff = celOffsetsOff; allCelsMask != 0; celOffsetOff += 2) {
|
||||
const icel = prop.cels.length
|
||||
const celbit = 0x80 >> icel
|
||||
const celOff = data.getUint16(celOffsetOff, LE)
|
||||
firstCelOff = Math.min(celOff, firstCelOff)
|
||||
prop.cels.push(decodeCel(new DataView(data.buffer, celOff), (prop.colorBitmask & celbit) != 0))
|
||||
allCelsMask = (allCelsMask << 1) & 0xff
|
||||
}
|
||||
prop.animations = decodeAnimations(data, graphicStateOff, firstCelOff, stateCount)
|
||||
return prop
|
||||
}
|
||||
|
||||
const decodeLimb = (data, limb) => {
|
||||
let frameCount = data.getUint8(0) + 1
|
||||
limb.frames = []
|
||||
for (let iframe = 0; iframe < frameCount; iframe ++) {
|
||||
limb.frames.push(data.getInt8(3 + iframe))
|
||||
}
|
||||
const celOffsetsOff = 3 + frameCount
|
||||
const maxCelIndex = Math.max(...limb.frames)
|
||||
limb.cels = []
|
||||
let firstCelOff
|
||||
for (let icel = 0; icel <= maxCelIndex; icel ++) {
|
||||
const celOff = data.getUint16(celOffsetsOff + (icel * 2), LE)
|
||||
if (icel == 0) {
|
||||
firstCelOff = celOff
|
||||
}
|
||||
limb.cels.push(decodeCel(new DataView(data.buffer, data.byteOffset + celOff)))
|
||||
}
|
||||
limb.animations = decodeAnimations(data, data.getUint8(2), firstCelOff, limb.frames.length)
|
||||
}
|
||||
|
||||
const choreographyActions = [
|
||||
"init", "stand", "walk", "hand_back", "sit_floor", "sit_chair", "bend_over",
|
||||
"bend_back", "point", "throw", "get_shot", "jump", "punch", "wave",
|
||||
"frown", "stand_back", "walk_front", "walk_back", "stand_front",
|
||||
"unpocket", "gimme", "knife", "arm_get", "hand_out", "operate",
|
||||
"arm_back", "shoot1", "shoot2", "nop", "sit_front"
|
||||
]
|
||||
|
||||
const decodeBody = (data) => {
|
||||
const body = {
|
||||
data: data,
|
||||
headCelNumber: data.getUint8(19),
|
||||
frozenWhenStands: data.getUint8(20),
|
||||
frontFacingLimbOrder: [],
|
||||
backFacingLimbOrder: [],
|
||||
limbs: [],
|
||||
choreography: [],
|
||||
actions: {}
|
||||
}
|
||||
for (let ilimb = 0; ilimb < 6; ilimb ++) {
|
||||
body.frontFacingLimbOrder.push(data.getUint8(27 + ilimb))
|
||||
body.backFacingLimbOrder.push(data.getUint8(33 + ilimb))
|
||||
const limb = {
|
||||
pattern: data.getUint8(21 + ilimb),
|
||||
affectedByHeight: data.getUint8(39 + ilimb)
|
||||
}
|
||||
const limbOff = data.getUint16(7 + (ilimb * 2), LE)
|
||||
decodeLimb(new DataView(data.buffer, limbOff), limb)
|
||||
body.limbs.push(limb)
|
||||
}
|
||||
const choreographyIndexOff = data.getUint16(0, LE)
|
||||
const choreographyTableOff = data.getUint16(2, LE)
|
||||
const indexToChoreography = new Map()
|
||||
for (const [i, action] of choreographyActions.entries()) {
|
||||
let tableIndex = data.getUint8(choreographyIndexOff + i)
|
||||
let choreographyIndex = indexToChoreography.get(tableIndex)
|
||||
if (choreographyIndex == undefined) {
|
||||
choreographyIndex = body.choreography.length
|
||||
indexToChoreography.set(tableIndex, choreographyIndex)
|
||||
const choreography = []
|
||||
body.choreography.push(choreography)
|
||||
for (;; tableIndex ++) {
|
||||
const state = data.getUint8(choreographyTableOff + tableIndex)
|
||||
let limb = (state & 0x70) >> 4
|
||||
let animation = state & 0x0f
|
||||
if (limb == 6) {
|
||||
limb = 5
|
||||
animation += 0x10
|
||||
}
|
||||
choreography.push({ limb, animation })
|
||||
if ((state & 0x80) != 0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
body.actions[action] = choreographyIndex
|
||||
}
|
||||
return body
|
||||
}
|
||||
|
||||
const celsFromMask = (prop, celMask) => {
|
||||
const cels = []
|
||||
for (let icel = 0; icel < 8; icel ++) {
|
||||
const celbit = 0x80 >> icel
|
||||
if ((celMask & celbit) != 0) {
|
||||
cels.push(prop.cels[icel])
|
||||
}
|
||||
}
|
||||
return cels
|
||||
}
|
||||
|
||||
const compositeCels = (cels, celColors = null, paintOrder = null) => {
|
||||
if (cels.length == 0) {
|
||||
return null
|
||||
}
|
||||
let minX = Number.POSITIVE_INFINITY
|
||||
let minY = Number.POSITIVE_INFINITY
|
||||
let maxX = Number.NEGATIVE_INFINITY
|
||||
let maxY = Number.NEGATIVE_INFINITY
|
||||
let xRel = 0
|
||||
let yRel = 0
|
||||
let layers = []
|
||||
for (const [icel, cel] of cels.entries()) {
|
||||
if (cel) {
|
||||
const x = cel.xOffset + xRel
|
||||
const y = -(cel.yOffset + yRel)
|
||||
minX = Math.min(minX, x)
|
||||
minY = Math.min(minY, y)
|
||||
maxX = Math.max(maxX, cel.width + x)
|
||||
maxY = Math.max(maxY, cel.height + y)
|
||||
if (cel.bitmap) {
|
||||
const colors = Array.isArray(celColors) ? celColors[icel] : (celColors ?? {})
|
||||
layers.push({ canvas: canvasFromBitmap(cel.bitmap, colors), x, y })
|
||||
} else {
|
||||
layers.push(null)
|
||||
}
|
||||
xRel += cel.xRel
|
||||
yRel += cel.yRel
|
||||
} else {
|
||||
layers.push(null)
|
||||
}
|
||||
}
|
||||
|
||||
if (paintOrder) {
|
||||
const reordered = []
|
||||
for (const ilayer of paintOrder) {
|
||||
reordered.push(layers[ilayer])
|
||||
}
|
||||
layers = reordered
|
||||
}
|
||||
|
||||
const w = (maxX - minX) * 8
|
||||
const h = maxY - minY
|
||||
|
||||
const canvas = makeCanvas(w, h)
|
||||
const ctx = canvas.getContext("2d")
|
||||
for (const layer of layers) {
|
||||
if (layer && layer.canvas) {
|
||||
ctx.drawImage(layer.canvas, (layer.x - minX) * 8, layer.y - minY)
|
||||
}
|
||||
}
|
||||
return { canvas: canvas, xOffset: minX * 8, yOffset: minY, w: w, h: h }
|
||||
}
|
||||
|
||||
const imageFromCanvas = (canvas) => {
|
||||
const img = document.createElement("img")
|
||||
img.src = canvas.toDataURL()
|
||||
img.width = canvas.width * 3
|
||||
img.height = canvas.height * 3
|
||||
img.style.imageRendering = "pixelated"
|
||||
return img
|
||||
}
|
||||
|
||||
const imageFromBitmap = (bitmap, colors = {}) => imageFromCanvas(canvasFromBitmap(bitmap, colors))
|
||||
|
||||
const textNode = (text, type = "span") => {
|
||||
const node = document.createElement(type)
|
||||
node.innerText = text
|
||||
return node
|
||||
}
|
||||
|
||||
const wrapLink = (element, href) => {
|
||||
const link = document.createElement("a")
|
||||
link.href = href
|
||||
link.appendChild(element)
|
||||
return link
|
||||
}
|
||||
|
||||
const PropImpl = {
|
||||
decode: decodeProp,
|
||||
detailHref: (filename) => `detail.html?f=${filename}`,
|
||||
celsForAnimationState: (prop, istate) => celsFromMask(prop, prop.celmasks[istate]),
|
||||
}
|
||||
|
||||
const LimbImpl = {
|
||||
celsForAnimationState: (limb, istate) => {
|
||||
const iframe = limb.frames[istate]
|
||||
if (iframe >= 0) {
|
||||
return [limb.cels[iframe]]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const actionOrientations = {
|
||||
"stand_back": "back",
|
||||
"walk_front": "front",
|
||||
"walk_back": "back",
|
||||
"stand_front": "front",
|
||||
"sit_front": "front"
|
||||
}
|
||||
const BodyImpl = {
|
||||
decode: decodeBody,
|
||||
detailHref: (filename) => `body.html?f=${filename}`,
|
||||
generateFrames: (action, body, frames) => {
|
||||
const chore = body.choreography[body.actions[action]]
|
||||
const animations = []
|
||||
const orientation = actionOrientations[action] ?? "side"
|
||||
const limbOrder = orientation == "front" ? body.frontFacingLimbOrder :
|
||||
orientation == "back" ? body.backFacingLimbOrder :
|
||||
null // side animations are always displayed in standard limb order
|
||||
for (const limb of body.limbs) {
|
||||
if (limb.animations.length > 0) {
|
||||
animations.push({ ...limb.animations[0] })
|
||||
} else {
|
||||
animations.push({ startState: 0, endState: 0 })
|
||||
}
|
||||
}
|
||||
for (const override of chore) {
|
||||
const ilimb = override.limb
|
||||
const newAnim = body.limbs[ilimb].animations[override.animation]
|
||||
animations[ilimb].startState = newAnim.startState
|
||||
animations[ilimb].endState = newAnim.endState
|
||||
}
|
||||
while (true) {
|
||||
const cels = []
|
||||
const celColors = []
|
||||
let restartedCount = 0
|
||||
for (const [ilimb, limb] of body.limbs.entries()) {
|
||||
const animation = animations[ilimb]
|
||||
if (animation.current == undefined) {
|
||||
animation.current = animation.startState
|
||||
} else {
|
||||
animation.current ++
|
||||
if (animation.current > animation.endState) {
|
||||
animation.current = animation.startState
|
||||
restartedCount ++
|
||||
}
|
||||
}
|
||||
const istate = limb.frames[animation.current]
|
||||
if (istate >= 0) {
|
||||
cels.push(limb.cels[istate])
|
||||
} else {
|
||||
cels.push(null)
|
||||
}
|
||||
celColors.push({ pattern: limb.pattern })
|
||||
}
|
||||
if (restartedCount == animations.length) {
|
||||
break
|
||||
}
|
||||
frames.push(compositeCels(cels, celColors, limbOrder))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const linkDetail = (element, filename, impl) => {
|
||||
return impl && impl.detailHref ? wrapLink(element, impl.detailHref(filename)) : element
|
||||
}
|
||||
|
||||
const createAnimation = (animation, value, impl) => {
|
||||
const frames = []
|
||||
if (impl.generateFrames) {
|
||||
impl.generateFrames(animation, value, frames)
|
||||
} else {
|
||||
for (let istate = animation.startState; istate <= animation.endState; istate ++) {
|
||||
const frame = compositeCels(impl.celsForAnimationState(value, istate))
|
||||
if (frame != null) {
|
||||
frames.push(frame)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (frames.length == 0) {
|
||||
return textNode("")
|
||||
} else if (frames.length == 1) {
|
||||
return imageFromCanvas(frames[0].canvas)
|
||||
}
|
||||
let minX = Number.POSITIVE_INFINITY
|
||||
let minY = Number.POSITIVE_INFINITY
|
||||
let maxX = Number.NEGATIVE_INFINITY
|
||||
let maxY = Number.NEGATIVE_INFINITY
|
||||
for (const frame of frames) {
|
||||
minX = Math.min(minX, frame.xOffset)
|
||||
minY = Math.min(minY, frame.yOffset)
|
||||
maxX = Math.max(maxX, frame.xOffset + frame.w)
|
||||
maxY = Math.max(maxY, frame.yOffset + frame.h)
|
||||
}
|
||||
|
||||
const w = maxX - minX
|
||||
const h = maxY - minY
|
||||
const canvas = makeCanvas(w, h)
|
||||
canvas.style.imageRendering = "pixelated"
|
||||
canvas.style.width = `${w * 3}px`
|
||||
canvas.style.height = `${h * 3}px`
|
||||
let iframe = 0
|
||||
const ctx = canvas.getContext("2d")
|
||||
const nextFrame = () => {
|
||||
const frame = frames[iframe]
|
||||
ctx.clearRect(0, 0, w, h)
|
||||
ctx.drawImage(frame.canvas, frame.xOffset - minX, frame.yOffset - minY)
|
||||
iframe = (iframe + 1) % frames.length
|
||||
}
|
||||
nextFrame()
|
||||
setInterval(nextFrame, 250)
|
||||
return canvas
|
||||
}
|
||||
|
||||
const showAnimations = (value, container, impl) => {
|
||||
for (const animation of value.animations) {
|
||||
container.appendChild(linkDetail(createAnimation(animation, value, impl), value.filename, impl))
|
||||
}
|
||||
}
|
||||
|
||||
const showStates = (prop, container) => {
|
||||
for (const celmask of prop.celmasks) {
|
||||
const state = compositeCels(celsFromMask(prop, celmask))
|
||||
if (state) {
|
||||
const img = imageFromCanvas(state.canvas)
|
||||
img.alt = prop.filename
|
||||
container.appendChild(linkDetail(img, prop.filename))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const showCels = (prop, container) => {
|
||||
for (const cel of prop.cels) {
|
||||
if (cel.canvas) {
|
||||
container.appendChild(imageFromCanvas(cel.canvas))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const decodeBinary = async (filename, impl) => {
|
||||
try {
|
||||
const prop = impl.decode(await readBinary(filename))
|
||||
prop.filename = filename
|
||||
return prop
|
||||
} catch (e) {
|
||||
return { filename: filename, error: e }
|
||||
}
|
||||
}
|
||||
|
||||
const showError = (e, filename, impl) => {
|
||||
const container = document.getElementById("errors")
|
||||
const errNode = document.createElement("p")
|
||||
console.error(e)
|
||||
errNode.appendChild(linkDetail(textNode(filename, "b"), filename, impl))
|
||||
errNode.appendChild(textNode(e.toString(), "p"))
|
||||
if (e.stack) {
|
||||
errNode.appendChild(textNode(e.stack.toString(), "pre"))
|
||||
}
|
||||
container.appendChild(errNode)
|
||||
}
|
||||
|
||||
const displayFile = async (filename, container, impl) => {
|
||||
const value = await decodeBinary(filename, impl)
|
||||
const displayFile = async (doc, container, filename, decode, show) => {
|
||||
const value = await decodeBinary(filename, decode)
|
||||
if (value.error) {
|
||||
container.parentNode.removeChild(container)
|
||||
showError(value.error, value.filename, impl)
|
||||
doc.showError(value.error, filename)
|
||||
} else {
|
||||
try {
|
||||
impl.display(value, container)
|
||||
showAll(doc, container, filename, [value], show)
|
||||
} catch (e) {
|
||||
container.parentNode.removeChild(container)
|
||||
showError(e, value.filename, impl)
|
||||
doc.showError(e, filename)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PropImpl.display = (prop, container) => {
|
||||
if (prop.filename == 'heads/fhead.bin') {
|
||||
container.appendChild(textNode("CW: Pixel genitals"))
|
||||
} else if (prop.animations.length > 0) {
|
||||
showAnimations(prop, container, PropImpl)
|
||||
} else {
|
||||
showStates(prop, container)
|
||||
}
|
||||
}
|
||||
|
||||
BodyImpl.display = (body, container) => {
|
||||
container.appendChild(linkDetail(createAnimation("walk", body, BodyImpl), body.filename, BodyImpl))
|
||||
}
|
||||
|
||||
const displayList = async (indexFile, containerId, impl) => {
|
||||
const displayList = async (doc, indexFile, containerId, decode, show) => {
|
||||
const response = await fetch(indexFile, { cache: "no-cache" })
|
||||
const filenames = await response.json()
|
||||
const container = document.getElementById(containerId)
|
||||
|
@ -897,8 +38,16 @@ const displayList = async (indexFile, containerId, impl) => {
|
|||
fileContainer.style.margin = "2px"
|
||||
fileContainer.style.padding = "2px"
|
||||
fileContainer.style.display = "inline-block"
|
||||
fileContainer.appendChild(linkDetail(textNode(filename, "div"), filename, impl))
|
||||
fileContainer.appendChild(doc.linkDetail(textNode(filename, "div"), filename))
|
||||
container.appendChild(fileContainer)
|
||||
displayFile(filename, fileContainer, impl)
|
||||
displayFile(doc, fileContainer, filename, decode, show)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const displayBodies = (indexFile, containerId) =>
|
||||
displayList(docBuilder({ detailHref: "body.html", errorContainer: document.getElementById("errors") }),
|
||||
indexFile, containerId, decodeBody, showBody)
|
||||
|
||||
export const displayProps = (indexFile, containerId) =>
|
||||
displayList(docBuilder({ detailHref: "detail.html", errorContainer: document.getElementById("errors") }),
|
||||
indexFile, containerId, decodeProp, showProp)
|
||||
|
|
7
mamelink/griddle/.dbxinit
Normal file
7
mamelink/griddle/.dbxinit
Normal file
|
@ -0,0 +1,7 @@
|
|||
alias r run -i test.i -g test.gri
|
||||
alias c cont
|
||||
alias n next
|
||||
alias s step
|
||||
alias p print
|
||||
alias l list
|
||||
alias q quit
|
23
mamelink/griddle/DOC
Normal file
23
mamelink/griddle/DOC
Normal file
|
@ -0,0 +1,23 @@
|
|||
/u0/chip/habitat/griddle:
|
||||
This directory contains the Griddle and Fred utilities. They share
|
||||
most of their source, since they are mostly the same program, so they are both
|
||||
together here. Fred uses Fastlink, so some stuff for it is elsewhere.
|
||||
|
||||
These are the files here:
|
||||
DOC - This file
|
||||
regiontools.t - Documentation for Fred and Griddle
|
||||
|
||||
Makefile - Makefile to compile everything
|
||||
*.c, *.y, *.h - Source files
|
||||
|
||||
fred - Executable for Fred
|
||||
griddle - Executable for Griddle
|
||||
|
||||
reno.out - Binary for C64 half of Fred (gets uploaded through Fastlink)
|
||||
|
||||
util - A directory containing some minor utilities that work with
|
||||
Fred. Fred keeps a stat file of what commands are used so
|
||||
We can collect frequency info for improving the command
|
||||
interface. These utilities deal with this stat file. The
|
||||
utilities are all short and their source is their
|
||||
documentation.
|
84
mamelink/griddle/Makefile
Normal file
84
mamelink/griddle/Makefile
Normal file
|
@ -0,0 +1,84 @@
|
|||
.SUFFIXES: .o .c .h .run .y .l
|
||||
|
||||
GOBJ = griddle.o gmain.o glexer.o build.o cv.o gexpr.o gexec.o debug.o indir.o
|
||||
FOBJ = griddle.o fmain.o flexer.o build.o cv.o fexpr.o fexec.o debug.o fred.o fred2.o fscreen.o sun.o map.o
|
||||
|
||||
.c.o:
|
||||
cc -c -g -DYYDEBUG $*.c
|
||||
|
||||
.y.c:
|
||||
yacc -vd $*.y
|
||||
mv y.tab.c $*.c
|
||||
|
||||
.l.c:
|
||||
lex $*.l
|
||||
mv lex.yy.c $*.c
|
||||
|
||||
.c.run:
|
||||
cc -o $* $*.c
|
||||
|
||||
griddle: $(GOBJ)
|
||||
cc -g $(GOBJ) -o griddle
|
||||
|
||||
fred: $(FOBJ)
|
||||
cc -g $(FOBJ) -o fred -lcurses -ltermlib
|
||||
|
||||
all: griddle fred
|
||||
|
||||
dumpfstats: dumpfstats.c
|
||||
cc -g dumpfstats.c -o dumpfstats
|
||||
|
||||
flushfstats: flushfstats.c
|
||||
cc -g flushfstats.c -o flushfstats
|
||||
|
||||
griddle.o: griddle.c griddleDefs.h
|
||||
#griddle.c: griddle.y
|
||||
|
||||
alloc.o: alloc.c
|
||||
|
||||
build.o: build.c griddleDefs.h
|
||||
|
||||
gmain.o: main.c griddleDefs.h
|
||||
cc -c -g -DYYDEBUG main.c
|
||||
mv main.o gmain.o
|
||||
|
||||
fmain.o: main.c griddleDefs.h
|
||||
cc -c -g -DYYDEBUG -DFRED main.c
|
||||
mv main.o fmain.o
|
||||
|
||||
gexec.o: exec.c griddleDefs.h
|
||||
cc -c -g -DYYDEBUG exec.c
|
||||
mv exec.o gexec.o
|
||||
|
||||
fexec.o: exec.c griddleDefs.h
|
||||
cc -c -g -DYYDEBUG -DFRED exec.c
|
||||
mv exec.o fexec.o
|
||||
|
||||
debug.o: debug.c griddleDefs.h
|
||||
|
||||
cv.o: cv.c griddleDefs.h
|
||||
|
||||
glexer.o: lexer.c griddleDefs.h y.tab.h
|
||||
cc -c -g -DYYDEBUG lexer.c
|
||||
mv lexer.o glexer.o
|
||||
|
||||
flexer.o: lexer.c griddleDefs.h y.tab.h
|
||||
cc -c -g -DYYDEBUG -DFRED lexer.c
|
||||
mv lexer.o flexer.o
|
||||
|
||||
gexpr.o: expr.c griddleDefs.h y.tab.h
|
||||
cc -c -g -DYYDEBUG expr.c
|
||||
mv expr.o gexpr.o
|
||||
|
||||
fexpr.o: expr.c griddleDefs.h y.tab.h
|
||||
cc -c -g -DYYDEBUG -DFRED expr.c
|
||||
mv expr.o fexpr.o
|
||||
|
||||
indir.o: indir.c griddleDefs.h
|
||||
|
||||
fred.o: fred.c griddleDefs.h prot.h
|
||||
cc -c -g -DDATE=\""`date`\"" fred.c
|
||||
|
||||
fred2.o: fred2.c griddleDefs.h
|
||||
|
||||
fscreen.o: fscreen.c griddleDefs.h
|
50
mamelink/griddle/alloc.c
Normal file
50
mamelink/griddle/alloc.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
int tag;
|
||||
} alloc;
|
||||
|
||||
#define MAXTAG 40;
|
||||
static int allocCount[MAXTAG] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
static int freeCount[MAXTAG] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
static int highTag = 0;
|
||||
|
||||
char *
|
||||
mymalloc(size, tag)
|
||||
int size;
|
||||
int tag;
|
||||
{
|
||||
alloc *result;
|
||||
|
||||
result = (alloc *) malloc(size + sizeof(alloc));
|
||||
if (tag > highTag)
|
||||
highTag = tag;
|
||||
allocCount[tag]++;
|
||||
result->tag = tag;
|
||||
++result;
|
||||
return((char *) result);
|
||||
}
|
||||
|
||||
void
|
||||
myfree(ptr)
|
||||
alloc *ptr;
|
||||
{
|
||||
--ptr;
|
||||
freeCount[ptr->tag]--;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
dumpAllocOrphans()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<=highTag; ++i)
|
||||
printf("%d %d/%d\n", i, allocCount[i], freeCount[i]);
|
||||
}
|
199
mamelink/griddle/build.c
Normal file
199
mamelink/griddle/build.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
#include "griddleDefs.h"
|
||||
|
||||
value *evaluate();
|
||||
|
||||
genericListHead *
|
||||
buildGenericList(list, new)
|
||||
genericListHead *list;
|
||||
int *new;
|
||||
{
|
||||
genericListHead *result;
|
||||
genericList *newList;
|
||||
|
||||
if (list == NULL) {
|
||||
result = typeAlloc(genericListHead);
|
||||
result->thing = new;
|
||||
result->next = NULL;
|
||||
result->last = (genericList *)result;
|
||||
} else {
|
||||
newList = typeAlloc(genericList);
|
||||
newList->thing = new;
|
||||
newList->next = NULL;
|
||||
list->last->next = newList;
|
||||
list->last = newList;
|
||||
result = list;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
fieldList *
|
||||
buildFieldList(list, new)
|
||||
fieldList *list;
|
||||
field *new;
|
||||
{
|
||||
return((fieldList *)buildGenericList(list, new));
|
||||
}
|
||||
|
||||
valueList *
|
||||
buildValueList(list, new)
|
||||
valueList *list;
|
||||
value *new;
|
||||
{
|
||||
return((valueList *)buildGenericList(list, new));
|
||||
}
|
||||
|
||||
objectList *
|
||||
buildObjectList(list, new)
|
||||
objectList *list;
|
||||
object *new;
|
||||
{
|
||||
return((objectList *)buildGenericList(list, new));
|
||||
}
|
||||
|
||||
exprList *
|
||||
buildExprList(list, new)
|
||||
exprList *list;
|
||||
expression *new;
|
||||
{
|
||||
return((exprList *)buildGenericList(list, new));
|
||||
}
|
||||
|
||||
propertyList *
|
||||
buildPropertyList(list, new)
|
||||
propertyList *list;
|
||||
property *new;
|
||||
{
|
||||
return((propertyList *)buildGenericList(list, new));
|
||||
}
|
||||
|
||||
stringList *
|
||||
buildStringList(list, new)
|
||||
stringList *list;
|
||||
char *new;
|
||||
{
|
||||
return((stringList *)buildGenericList(list, new));
|
||||
}
|
||||
|
||||
expression *
|
||||
buildExpr(type, arg1, arg2, arg3)
|
||||
exprType type;
|
||||
int arg1;
|
||||
int arg2;
|
||||
int arg3;
|
||||
{
|
||||
expression *result;
|
||||
|
||||
result = typeAlloc(expression);
|
||||
result->type = type;
|
||||
result->part1 = arg1;
|
||||
result->part2 = arg2;
|
||||
result->part3 = arg3;
|
||||
return(result);
|
||||
}
|
||||
|
||||
property *
|
||||
buildProperty(fieldName, data)
|
||||
symbol *fieldName;
|
||||
exprList *data;
|
||||
{
|
||||
property *result;
|
||||
|
||||
result = typeAlloc(property);
|
||||
result->fieldName = fieldName;
|
||||
result->data = data;
|
||||
return(result);
|
||||
}
|
||||
|
||||
value *
|
||||
buildValue(vtype, val)
|
||||
valueType vtype;
|
||||
int val;
|
||||
{
|
||||
value *result;
|
||||
|
||||
result = typeAlloc(value);
|
||||
result->value = val;
|
||||
result->dataType = vtype;
|
||||
return(result);
|
||||
}
|
||||
|
||||
value *
|
||||
buildNumber(val)
|
||||
int val;
|
||||
{
|
||||
return(buildValue(VAL_INTEGER, val));
|
||||
}
|
||||
|
||||
value *
|
||||
buildString(val)
|
||||
char *val;
|
||||
{
|
||||
return(buildValue(VAL_STRING, (int)val));
|
||||
}
|
||||
|
||||
value *
|
||||
buildBitString(val)
|
||||
byte *val;
|
||||
{
|
||||
return(buildValue(VAL_BITSTRING, (int)val));
|
||||
}
|
||||
|
||||
field *
|
||||
buildField(name, dimension, type, initList)
|
||||
symbol *name;
|
||||
expression *dimension;
|
||||
fieldType type;
|
||||
exprList *initList;
|
||||
{
|
||||
field *result;
|
||||
value *val;
|
||||
|
||||
result = typeAlloc(field);
|
||||
result->name = name;
|
||||
result->type = type;
|
||||
result->offset = 0;
|
||||
result->invisible = FALSE;
|
||||
val = evaluate(dimension);
|
||||
if (isInteger(val) && val->value > 0)
|
||||
result->dimension = val->value;
|
||||
else {
|
||||
error("illegal data type for field dimension\n");
|
||||
result->dimension = 1;
|
||||
}
|
||||
freeValue(val);
|
||||
result->initValues = initList;
|
||||
return(result);
|
||||
}
|
||||
|
||||
field *
|
||||
invisifyField(aField)
|
||||
field *aField;
|
||||
{
|
||||
aField->invisible = TRUE;
|
||||
return(aField);
|
||||
}
|
||||
|
||||
objectTail *
|
||||
buildObjectTail(idExpr, propList)
|
||||
expression *idExpr;
|
||||
propertyList *propList;
|
||||
{
|
||||
objectTail *result;
|
||||
|
||||
result = typeAlloc(objectTail);
|
||||
result->idExpr = idExpr;
|
||||
result->properties = propList;
|
||||
return(result);
|
||||
}
|
||||
|
||||
objectStub *
|
||||
buildObjectStub(obj)
|
||||
object *obj;
|
||||
{
|
||||
objectStub *result;
|
||||
|
||||
result = typeAlloc(objectStub);
|
||||
result->class = obj->class;
|
||||
result->id = getLong(obj->stateVector, 0);
|
||||
return(result);
|
||||
}
|
346
mamelink/griddle/cv.c
Normal file
346
mamelink/griddle/cv.c
Normal file
|
@ -0,0 +1,346 @@
|
|||
#include "griddleDefs.h"
|
||||
|
||||
#define CLASS_MAX 256
|
||||
#define SIZE_OFFSET 12
|
||||
int classSize[CLASS_MAX];
|
||||
|
||||
byte cv[512];
|
||||
int cvLength;
|
||||
|
||||
static FILE *cvFyle;
|
||||
static object *inNoid[MAXNOID];
|
||||
|
||||
void
|
||||
cvByte(n)
|
||||
byte n;
|
||||
{
|
||||
cv[cvLength++] = n;
|
||||
}
|
||||
|
||||
byte
|
||||
readByte(fyle)
|
||||
FILE *fyle;
|
||||
{
|
||||
return((byte)getc(fyle));
|
||||
}
|
||||
|
||||
word
|
||||
readWord(fyle)
|
||||
FILE *fyle;
|
||||
{
|
||||
byte lo;
|
||||
byte hi;
|
||||
|
||||
lo = readByte(fyle);
|
||||
hi = readByte(fyle);
|
||||
return((hi << 8) + lo);
|
||||
}
|
||||
|
||||
void
|
||||
readClassFile()
|
||||
{
|
||||
int i;
|
||||
FILE *classFyle;
|
||||
|
||||
|
||||
if ((classFyle = fopen(classFileName, "r")) == NULL)
|
||||
systemError("can't open class file '%s'\n", classFileName);
|
||||
for (i=0; i<CLASS_MAX; ++i)
|
||||
classSize[i] = readWord(classFyle);
|
||||
for (i=0; i<CLASS_MAX; ++i)
|
||||
if (classSize[i] == 0xFFFF)
|
||||
classSize[i] = 0;
|
||||
else {
|
||||
fseek(classFyle, classSize[i]+SIZE_OFFSET, 0);
|
||||
classSize[i] = (readByte(classFyle) & 0x7F) - 6;
|
||||
}
|
||||
fclose(classFyle);
|
||||
}
|
||||
|
||||
void
|
||||
cvNoidClass()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=1; i<objectCount; ++i) {
|
||||
if (noidArray[i] != NULL) {
|
||||
cvByte(i);
|
||||
cvByte(noidArray[i]->class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cvProperties(class, buf)
|
||||
int class;
|
||||
byte *buf;
|
||||
{
|
||||
int container;
|
||||
int i;
|
||||
|
||||
if (class == 0) {
|
||||
cvByte(0); /* style */
|
||||
cvByte(getWord(buf, LIGHTLEVEL_OFFSET_REG));
|
||||
cvByte(getWord(buf, DEPTH_OFFSET_REG));
|
||||
cvByte(getWord(buf, CLASSGROUP_OFFSET_REG));
|
||||
cvByte(0); /* who am I? */
|
||||
cvByte(0); /* bank balance */
|
||||
cvByte(0);
|
||||
cvByte(0);
|
||||
cvByte(0);
|
||||
} else if (class == 1) {
|
||||
container = getLong(buf, CONTAINER_OFFSET_AVA);
|
||||
if (container != 0 && (container < -1000-MAXNOID ||
|
||||
-1000 <= container)) {
|
||||
error("specified avatar container out of range\n");
|
||||
return;
|
||||
}
|
||||
cvByte(getByte(buf, STYLE_OFFSET_AVA));
|
||||
cvByte(getWord(buf, X_OFFSET_AVA));
|
||||
cvByte(getWord(buf, Y_OFFSET_AVA));
|
||||
cvByte(getWord(buf, ORIENT_OFFSET_AVA));
|
||||
cvByte(getWord(buf, GRSTATE_OFFSET_AVA));
|
||||
if (container == 0)
|
||||
cvByte(0);
|
||||
else
|
||||
cvByte(-container-1001);
|
||||
for (i=0; i<AVATAR_PROPERTY_COUNT; ++i)
|
||||
cvByte(getWord(buf, PROP_BASE_AVA + i*2));
|
||||
} else {
|
||||
container = getLong(buf, CONTAINER_OFFSET_OBJ);
|
||||
if (container != 0 && (container < -1000-MAXNOID ||
|
||||
-1000 <= container)) {
|
||||
error("specified object container out of range\n");
|
||||
return;
|
||||
}
|
||||
cvByte(getWord(buf, STYLE_OFFSET_OBJ));
|
||||
cvByte(getWord(buf, X_OFFSET_OBJ));
|
||||
cvByte(getWord(buf, Y_OFFSET_OBJ));
|
||||
cvByte(getWord(buf, ORIENT_OFFSET_OBJ));
|
||||
cvByte(getWord(buf, GRSTATE_OFFSET_OBJ));
|
||||
if (container == 0)
|
||||
cvByte(0);
|
||||
else
|
||||
cvByte(-container-1001);
|
||||
for (i=0; i<classSize[class]; ++i)
|
||||
cvByte(getWord(buf, objectBase + i*2));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cvProps()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=1; i<objectCount; ++i)
|
||||
if (noidArray[i] != NULL)
|
||||
cvProperties(noidArray[i]->class, noidArray[i]->stateVector);
|
||||
}
|
||||
|
||||
boolean
|
||||
generateContentsVector()
|
||||
{
|
||||
int i;
|
||||
|
||||
cvLength = 0;
|
||||
if (noidArray[0] == NULL || noidArray[0]->class != 0) {
|
||||
error("first object is not a region\n");
|
||||
return(FALSE);
|
||||
} else for (i=1; i<objectCount; ++i) {
|
||||
if (noidArray[i] != NULL && noidArray[i]->class == 0) {
|
||||
error("more than one region given\n");
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
/* cvProperties(0, noidArray[0]->stateVector);*/
|
||||
cvNoidClass();
|
||||
cvByte(0);
|
||||
cvProps();
|
||||
cvByte(0);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
outputContentsVector()
|
||||
{
|
||||
if (generateContentsVector())
|
||||
fwrite(cv, 1, cvLength, cvFile);
|
||||
}
|
||||
|
||||
void
|
||||
fillFromCvFile(obj)
|
||||
object *obj;
|
||||
{
|
||||
byte *buf;
|
||||
int class;
|
||||
int container;
|
||||
int i;
|
||||
|
||||
buf = obj->stateVector;
|
||||
class = obj->class;
|
||||
if (class == 0) {
|
||||
readByte(cvFyle); /* skip style */
|
||||
fillWord(buf, LIGHTLEVEL_OFFSET_REG, readByte(cvFyle));
|
||||
fillWord(buf, DEPTH_OFFSET_REG, readByte(cvFyle));
|
||||
fillWord(buf, CLASSGROUP_OFFSET_REG, readByte(cvFyle));
|
||||
readByte(cvFyle); /* skip who am i */
|
||||
for (i=0; i<4; ++i)
|
||||
readByte(cvFyle); /* skip bank balance */
|
||||
} else if (class == 1) {
|
||||
fillByte(buf, STYLE_OFFSET_AVA, readByte(cvFyle));
|
||||
fillWord(buf, X_OFFSET_AVA, readByte(cvFyle));
|
||||
fillWord(buf, Y_OFFSET_AVA, readByte(cvFyle));
|
||||
fillWord(buf, ORIENT_OFFSET_AVA, readByte(cvFyle));
|
||||
fillWord(buf, GRSTATE_OFFSET_AVA, readByte(cvFyle));
|
||||
container = getLong(inNoid[readByte(cvFyle)]->stateVector, 0);
|
||||
fillLong(buf, CONTAINER_OFFSET_AVA, container);
|
||||
for (i=0; i<AVATAR_PROPERTY_COUNT; ++i)
|
||||
fillWord(buf, PROP_BASE_AVA + i*2, readByte(cvFyle));
|
||||
} else {
|
||||
fillWord(buf, STYLE_OFFSET_OBJ, readByte(cvFyle));
|
||||
fillWord(buf, X_OFFSET_OBJ, readByte(cvFyle));
|
||||
fillWord(buf, Y_OFFSET_OBJ, readByte(cvFyle));
|
||||
fillWord(buf, ORIENT_OFFSET_OBJ, readByte(cvFyle));
|
||||
fillWord(buf, GRSTATE_OFFSET_OBJ, readByte(cvFyle));
|
||||
container = getLong(inNoid[readByte(cvFyle)]->stateVector, 0);
|
||||
fillLong(buf, CONTAINER_OFFSET_OBJ, container);
|
||||
for (i=0; i<classSize[class]; ++i)
|
||||
fillWord(buf, objectBase + i*2, readByte(cvFyle));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
inputContentsVector(filename)
|
||||
char *filename;
|
||||
{
|
||||
int i;
|
||||
int noid;
|
||||
int class;
|
||||
int highNoid;
|
||||
int noidBase;
|
||||
byte noidMap[MAXNOID];
|
||||
object *initObject();
|
||||
|
||||
if ((cvFyle = fopen(filename, "r")) == NULL) {
|
||||
error("can't open contents vector input file '%s'\n",
|
||||
filename);
|
||||
return;
|
||||
}
|
||||
for (i=0; i<MAXNOID; ++i)
|
||||
inNoid[i] = NULL;
|
||||
noidMap[0] = 0;
|
||||
inNoid[0] = initObject(0, -globalIdCounter++);
|
||||
noidBase = 1;
|
||||
do {
|
||||
for (highNoid=noidBase; (noid = readByte(cvFyle)) != 0; ++highNoid) {
|
||||
class = readByte(cvFyle);
|
||||
noidMap[highNoid] = noid;
|
||||
inNoid[noid] = initObject(class, -globalIdCounter++);
|
||||
}
|
||||
for (i=noidBase; i<highNoid; ++i)
|
||||
fillFromCvFile(inNoid[noidMap[i]]);
|
||||
for (i=0; i<highNoid; ++i) {
|
||||
if (objectCount < MAXNOID)
|
||||
noidArray[objectCount++] = inNoid[noidMap[i]];
|
||||
if (griFile != NULL)
|
||||
dumpObject(inNoid[noidMap[i]]);
|
||||
if (rawFile != NULL)
|
||||
outputRawObject(inNoid[noidMap[i]]);
|
||||
}
|
||||
noidBase = 0;
|
||||
} while (readByte(cvFyle) != 0 && !feof(cvFyle));
|
||||
fclose(cvFyle);
|
||||
}
|
||||
|
||||
int
|
||||
deCvNoidClass(offset)
|
||||
int offset;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (; cv[offset] != 0; offset += 2)
|
||||
;
|
||||
return(offset + 1);
|
||||
}
|
||||
|
||||
int
|
||||
deCvProperties(class, buf, offset)
|
||||
int class;
|
||||
byte *buf;
|
||||
int offset;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (class == 0) {
|
||||
fillWord(buf, LIGHTLEVEL_OFFSET_REG, cv[offset + 1]);
|
||||
fillWord(buf, DEPTH_OFFSET_REG, cv[offset + 2]);
|
||||
fillWord(buf, CLASSGROUP_OFFSET_REG, cv[offset + 3]);
|
||||
return(9);
|
||||
} else if (class == 1) {
|
||||
fillByte(buf, STYLE_OFFSET_AVA, cv[offset + 0]);
|
||||
fillWord(buf, X_OFFSET_AVA, cv[offset + 1]);
|
||||
fillWord(buf, Y_OFFSET_AVA, cv[offset + 2]);
|
||||
fillWord(buf, ORIENT_OFFSET_AVA, cv[offset + 3]);
|
||||
fillWord(buf, GRSTATE_OFFSET_AVA, cv[offset + 4]);
|
||||
if (cv[offset + 5] == 0)
|
||||
fillLong(buf, CONTAINER_OFFSET_AVA, 0);
|
||||
else
|
||||
fillLong(buf, CONTAINER_OFFSET_AVA, -1001-cv[offset+5]);
|
||||
for (i=0; i<AVATAR_PROPERTY_COUNT; ++i)
|
||||
fillWord(buf, PROP_BASE_AVA + i*2, cv[offset + 6+i]);
|
||||
return(6 + AVATAR_PROPERTY_COUNT);
|
||||
} else {
|
||||
fillWord(buf, STYLE_OFFSET_OBJ, cv[offset + 0]);
|
||||
fillWord(buf, X_OFFSET_OBJ, cv[offset + 1]);
|
||||
fillWord(buf, Y_OFFSET_OBJ, cv[offset + 2]);
|
||||
fillWord(buf, ORIENT_OFFSET_OBJ, cv[offset + 3]);
|
||||
fillWord(buf, GRSTATE_OFFSET_OBJ, cv[offset + 4]);
|
||||
fillLong(buf, CONTAINER_OFFSET_OBJ, -1001-cv[offset + 5]);
|
||||
for (i=0; i<classSize[class]; ++i)
|
||||
fillWord(buf, objectBase + i*2, cv[offset + 6 + i]);
|
||||
return(6 + classSize[class]);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
deCvProps(noidOffset, stateOffset)
|
||||
int noidOffset;
|
||||
int stateOffset;
|
||||
{
|
||||
int noid;
|
||||
|
||||
while ((noid = cv[noidOffset]) != 0) {
|
||||
if (cv[noidOffset + 1] != noidArray[noid]->class) {
|
||||
error("class mismatch: cv says %d, we say %d\n",
|
||||
cv[noidOffset + 1], noidArray[noid]->class);
|
||||
return(0);
|
||||
}
|
||||
stateOffset += deCvProperties(noidArray[noid]->class,
|
||||
noidArray[noid]->stateVector, stateOffset);
|
||||
noidOffset += 2;
|
||||
noidAlive[noid] = TRUE;
|
||||
}
|
||||
if (cv[stateOffset] == 0)
|
||||
return(0);
|
||||
else
|
||||
return(stateOffset + 1);
|
||||
}
|
||||
|
||||
void
|
||||
degenerateContentsVector()
|
||||
{
|
||||
int offset;
|
||||
int noid;
|
||||
|
||||
noidAlive[0] = TRUE;
|
||||
for (noid=1; noid<MAXNOID; ++noid)
|
||||
noidAlive[noid] = FALSE;
|
||||
offset = 0;
|
||||
while ((offset = deCvProps(offset, deCvNoidClass(offset))) != 0)
|
||||
;
|
||||
for (noid=1; noid<MAXNOID; ++noid)
|
||||
if (!noidAlive[noid] && noidArray[noid] != NULL) {
|
||||
freeObject(noidArray[noid]);
|
||||
noidArray[noid] = NULL;
|
||||
}
|
||||
}
|
170
mamelink/griddle/debug.c
Normal file
170
mamelink/griddle/debug.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
#include "griddleDefs.h"
|
||||
|
||||
int
|
||||
getByte(buf, offset)
|
||||
byte *buf;
|
||||
int offset;
|
||||
{
|
||||
return((char)buf[offset]);
|
||||
}
|
||||
|
||||
int
|
||||
getWord(buf, offset)
|
||||
byte *buf;
|
||||
int offset;
|
||||
{
|
||||
return((short)( buf[offset ] * 256 +
|
||||
buf[offset + 1] ));
|
||||
}
|
||||
|
||||
int
|
||||
getLong(buf, offset)
|
||||
byte *buf;
|
||||
int offset;
|
||||
{
|
||||
return( buf[offset ] * 256 * 256 * 256 +
|
||||
buf[offset + 1] * 256 * 256 +
|
||||
buf[offset + 2] * 256 +
|
||||
buf[offset + 3] );
|
||||
}
|
||||
|
||||
char
|
||||
contCode(ctype)
|
||||
int ctype;
|
||||
{
|
||||
if (ctype == 0) return('r');
|
||||
else if (ctype == 1) return('a');
|
||||
else /* if (ctype == 2) */ return('o');
|
||||
}
|
||||
|
||||
void
|
||||
dumpField(aField, buf)
|
||||
field *aField;
|
||||
byte *buf;
|
||||
{
|
||||
char str[512];
|
||||
|
||||
if (fieldString(aField, buf, str))
|
||||
fprintf(griFile, " %s\n", str);
|
||||
}
|
||||
|
||||
boolean
|
||||
fieldString(aField, buf, str)
|
||||
field *aField;
|
||||
byte *buf;
|
||||
char *str;
|
||||
{
|
||||
int i;
|
||||
int offset, bitOffset;
|
||||
int val;
|
||||
char *escape();
|
||||
char temp[80];
|
||||
|
||||
if (aField->invisible) {
|
||||
*str = '\0';
|
||||
return(FALSE);
|
||||
}
|
||||
sprintf(str, "%s: ", aField->name->name);
|
||||
offset = aField->offset & 0x3FFF;
|
||||
bitOffset = aField->offset >> 14;
|
||||
for (i=0; i<aField->dimension; ++i) {
|
||||
switch (aField->type) {
|
||||
Case FIELD_ENTITY:
|
||||
sprintf(temp, "%c %d",
|
||||
contCode(getWord(buf, offset + 6*i + 4)),
|
||||
getLong(buf, offset + 6*i));
|
||||
|
||||
Case FIELD_BIN31:
|
||||
val = getLong(buf, offset + 4*i);
|
||||
sprintf(temp, "%d", val);
|
||||
|
||||
Case FIELD_AVAID:
|
||||
val = getLong(buf, offset + 4*i);
|
||||
sprintf(temp, "a %d", val);
|
||||
|
||||
Case FIELD_OBJID:
|
||||
val = getLong(buf, offset + 4*i);
|
||||
sprintf(temp, "o %d", val);
|
||||
|
||||
Case FIELD_REGID:
|
||||
val = getLong(buf, offset + 4*i);
|
||||
sprintf(temp, "r %d", val);
|
||||
|
||||
Case FIELD_FATWORD:
|
||||
val = getWord(buf, offset + 4*i) +
|
||||
getWord(buf, offset + 4*i + 2) * 256;
|
||||
sprintf(temp, "%d", val);
|
||||
|
||||
Case FIELD_BIN15:
|
||||
val = getWord(buf, offset + 2*i);
|
||||
sprintf(temp, "%d", val);
|
||||
|
||||
Case FIELD_WORDS:
|
||||
val = getWord(buf, offset + 2*i);
|
||||
sprintf(temp, "%s%s%s",
|
||||
(i == 0) ? "\"" : "",
|
||||
escape(val),
|
||||
(i == aField->dimension-1) ? "\"" : ""
|
||||
);
|
||||
|
||||
Case FIELD_BYTE:
|
||||
val = getByte(buf, offset);
|
||||
sprintf(temp, "%d", val);
|
||||
|
||||
Case FIELD_VARSTRING:
|
||||
val = getWord(buf, offset);
|
||||
strcpy(temp, "\"");
|
||||
strncat(temp, buf + offset + 2, val);
|
||||
strcat(temp, "\"");
|
||||
i = aField->dimension - 1;
|
||||
|
||||
Case FIELD_CHARACTER:
|
||||
val = getByte(buf, offset + i);
|
||||
sprintf(temp, "%s%s%s",
|
||||
(i == 0) ? "\"" : "",
|
||||
escape(val),
|
||||
(i == aField->dimension-1) ? "\"" : ""
|
||||
);
|
||||
|
||||
Case FIELD_BIT:
|
||||
val = getByte(buf, offset + ((i+bitOffset)>>3));
|
||||
val &= 1 << (7 - ((i+bitOffset)&7));
|
||||
sprintf(temp, "%s%c%s",
|
||||
(i == 0) ? "'" : "" ,
|
||||
(val) ? '1' : '0',
|
||||
(i == aField->dimension-1) ? "'b" : ""
|
||||
);
|
||||
}
|
||||
strcat(str, temp);
|
||||
if (aField->type != FIELD_WORDS && aField->type !=
|
||||
FIELD_BIT && aField->type != FIELD_CHARACTER &&
|
||||
i != aField->dimension-1)
|
||||
strcat(str, ", ");
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
dumpObject(obj)
|
||||
object *obj;
|
||||
{
|
||||
fieldList *fields;
|
||||
|
||||
if (obj == NULL)
|
||||
return;
|
||||
fprintf(griFile, "use %s {\n", classDefs[obj->class+1]->className->
|
||||
name);
|
||||
if (obj->class > 1) {
|
||||
fields = classDefs[0]->fields;
|
||||
while (fields != NULL) {
|
||||
dumpField(fields->field, obj->stateVector);
|
||||
fields = fields->nextField;
|
||||
}
|
||||
}
|
||||
fields = classDefs[obj->class+1]->fields;
|
||||
while (fields != NULL) {
|
||||
dumpField(fields->field, obj->stateVector);
|
||||
fields = fields->nextField;
|
||||
}
|
||||
fprintf(griFile, "}\n");
|
||||
}
|
771
mamelink/griddle/exec.c
Normal file
771
mamelink/griddle/exec.c
Normal file
|
@ -0,0 +1,771 @@
|
|||
#include "griddleDefs.h"
|
||||
|
||||
void
|
||||
executeInclude(filename)
|
||||
char *filename;
|
||||
{
|
||||
fileList *newFile;
|
||||
|
||||
if (announceIncludes) {
|
||||
fprintf(stderr, "->%s\n", filename);
|
||||
fflush(stderr);
|
||||
}
|
||||
newFile = typeAlloc(fileList);
|
||||
newFile->next = inputStack;
|
||||
newFile->saveName = currentFileName;
|
||||
newFile->saveLine = currentLineNumber;
|
||||
newFile->fyle = currentInput;
|
||||
inputStack = newFile;
|
||||
if ((currentInput = fopen(filename, "r")) == NULL) {
|
||||
error("unable to open include file '%s'\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
currentFileName = filename;
|
||||
currentLineNumber = 1;
|
||||
free(filename);
|
||||
}
|
||||
|
||||
void
|
||||
executeAssignment(name, expr)
|
||||
symbol *name;
|
||||
expression *expr;
|
||||
{
|
||||
value *evaluate();
|
||||
|
||||
if (name->type != NON_SYM && name->type != VARIABLE_SYM) {
|
||||
error("illegal assignment to '%s'\n", name->name);
|
||||
} else {
|
||||
if (name->type == VARIABLE_SYM)
|
||||
freeValue(name->def.value);
|
||||
name->type = VARIABLE_SYM;
|
||||
name->def.value = evaluate(expr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fillByte(buf, offset, value)
|
||||
byte *buf;
|
||||
int offset;
|
||||
int value;
|
||||
{
|
||||
buf[offset] = value & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
fillWord(buf, offset, value)
|
||||
byte *buf;
|
||||
int offset;
|
||||
int value;
|
||||
{
|
||||
buf[offset ] = (value >> 8) & 0xFF;
|
||||
buf[offset + 1] = value & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
fillLong(buf, offset, value)
|
||||
byte *buf;
|
||||
int offset;
|
||||
long value;
|
||||
{
|
||||
buf[offset ] = (value >> 24) & 0xFF;
|
||||
buf[offset + 1] = (value >> 16) & 0xFF;
|
||||
buf[offset + 2] = (value >> 8) & 0xFF;
|
||||
buf[offset + 3] = value & 0xFF;
|
||||
}
|
||||
|
||||
value *
|
||||
nextValue(dataptr)
|
||||
exprList **dataptr;
|
||||
{
|
||||
exprList *data;
|
||||
value *val;
|
||||
value *buildNumber();
|
||||
|
||||
if (dataptr == NULL || *dataptr == NULL)
|
||||
return(buildNumber(0));
|
||||
data = *dataptr;
|
||||
val = evaluate(data->expr);
|
||||
*dataptr = data->nextExpr;
|
||||
return(val);
|
||||
}
|
||||
|
||||
value *
|
||||
nextIntValue(dataptr)
|
||||
exprList **dataptr;
|
||||
{
|
||||
value *val;
|
||||
|
||||
val = nextValue(dataptr);
|
||||
if (!isInteger(val))
|
||||
val = buildNumber(0);
|
||||
return(val);
|
||||
}
|
||||
|
||||
char *
|
||||
nextStringValue(dataptr)
|
||||
exprList **dataptr;
|
||||
{
|
||||
value *val;
|
||||
char *result;
|
||||
|
||||
if (dataptr == NULL || *dataptr == NULL)
|
||||
return(NULL);
|
||||
val = nextValue(dataptr);
|
||||
if (isString(val))
|
||||
result = (char *)(val->value);
|
||||
else
|
||||
result = NULL;
|
||||
freeValue(val);
|
||||
return(result);
|
||||
}
|
||||
|
||||
int
|
||||
contNum(vtype)
|
||||
valueType vtype;
|
||||
{
|
||||
if (vtype == VAL_AVATAR) return (1);
|
||||
else if (vtype == VAL_OBJECT) return (2);
|
||||
else return (0);
|
||||
}
|
||||
|
||||
void
|
||||
adjustValue(val)
|
||||
value *val;
|
||||
{
|
||||
if (indirFile != NULL && val->value < -1000)
|
||||
val->value -= globalIdAdjustment;
|
||||
}
|
||||
|
||||
void
|
||||
fillField(buf, data, aField, nextInt, nextString, nextBit)
|
||||
byte *buf;
|
||||
exprList *data;
|
||||
field *aField;
|
||||
value *(*nextInt)();
|
||||
char *(*nextString)();
|
||||
value *(*nextBit)();
|
||||
{
|
||||
int i, j;
|
||||
int offset, bitOffset;
|
||||
int len;
|
||||
value *val;
|
||||
char *string;
|
||||
byte *bitString;
|
||||
int bitLength;
|
||||
int bufIndex;
|
||||
byte theBit;
|
||||
|
||||
offset = aField->offset & 0x3FFF;
|
||||
if (indirFile != NULL && offset == IDENT_OFFSET)
|
||||
return;
|
||||
bitOffset = aField->offset >> 14;
|
||||
|
||||
for (i=0; i<aField->dimension; ++i) {
|
||||
switch (aField->type) {
|
||||
Case FIELD_ENTITY:
|
||||
val = (*nextInt)(&data);
|
||||
adjustValue(val);
|
||||
fillLong(buf, offset + 6*i, val->value);
|
||||
fillWord(buf, offset + 6*i + 4, contNum(val->dataType));
|
||||
freeValue(val);
|
||||
|
||||
Case FIELD_AVAID:
|
||||
val = (*nextInt)(&data);
|
||||
if (val->dataType != VAL_AVATAR && val->dataType !=
|
||||
VAL_INTEGER)
|
||||
error("illegal avatar id value\n");
|
||||
adjustValue(val);
|
||||
fillLong(buf, offset + 4*i, val->value);
|
||||
freeValue(val);
|
||||
|
||||
Case FIELD_OBJID:
|
||||
val = (*nextInt)(&data);
|
||||
if (val->dataType != VAL_OBJECT && val->dataType !=
|
||||
VAL_INTEGER)
|
||||
error("illegal object id value\n");
|
||||
adjustValue(val);
|
||||
fillLong(buf, offset + 4*i, val->value);
|
||||
freeValue(val);
|
||||
|
||||
Case FIELD_REGID:
|
||||
val = (*nextInt)(&data);
|
||||
if (val->dataType != VAL_REGION && val->dataType !=
|
||||
VAL_INTEGER)
|
||||
error("illegal region id value\n");
|
||||
adjustValue(val);
|
||||
fillLong(buf, offset + 4*i, val->value);
|
||||
freeValue(val);
|
||||
|
||||
Case FIELD_BIN31:
|
||||
val = (*nextInt)(&data);
|
||||
fillLong(buf, offset + 4*i, val->value);
|
||||
freeValue(val);
|
||||
|
||||
Case FIELD_FATWORD:
|
||||
val = (*nextInt)(&data);
|
||||
fillWord(buf, offset + 4*i, val->value & 0xFF);
|
||||
fillWord(buf, offset + 4*i + 2, (val->value >> 8) &
|
||||
0xFF);
|
||||
freeValue(val);
|
||||
|
||||
Case FIELD_BIN15:
|
||||
val = (*nextInt)(&data);
|
||||
fillWord(buf, offset + 2*i, val->value);
|
||||
freeValue(val);
|
||||
|
||||
Case FIELD_WORDS:
|
||||
string = (*nextString)(&data);
|
||||
if (string != NULL)
|
||||
for (; i<aField->dimension && string != NULL
|
||||
&& string[i] != '\0'; ++i)
|
||||
fillWord(buf, offset + i*2, string[i]);
|
||||
for (; i<aField->dimension; ++i)
|
||||
fillWord(buf, offset + i*2, ' ');
|
||||
free(string);
|
||||
|
||||
Case FIELD_BYTE:
|
||||
val = (*nextInt)(&data);
|
||||
fillByte(buf, offset + i, val->value);
|
||||
freeValue(val);
|
||||
|
||||
Case FIELD_CHARACTER:
|
||||
string = (*nextString)(&data);
|
||||
if (string != NULL)
|
||||
for (; i<aField->dimension && string != NULL
|
||||
&& string[i] != '\0'; ++i)
|
||||
fillByte(buf, offset + i, string[i]);
|
||||
for (; i<aField->dimension; ++i)
|
||||
fillByte(buf, offset + i, ' ');
|
||||
freeValue(string);
|
||||
|
||||
Case FIELD_VARSTRING:
|
||||
string = (*nextString)(&data);
|
||||
if (string != NULL) {
|
||||
len = strlen(string);
|
||||
fillWord(buf, offset, len);
|
||||
for (; i<aField->dimension && string != NULL
|
||||
&& string[i] != '\0'; ++i)
|
||||
fillByte(buf, offset+2+i, string[i]);
|
||||
free(string);
|
||||
} else
|
||||
fillWord(buf, offset, 0);
|
||||
i = aField->dimension;
|
||||
|
||||
Case FIELD_BIT:
|
||||
val = (*nextBit)(&data);
|
||||
if (isInteger(val)) {
|
||||
bufIndex = offset + ((i+bitOffset)>>3);
|
||||
theBit = 1 << (7 - ((i+bitOffset)&7));
|
||||
if (val->value & 1)
|
||||
buf[bufIndex] |= theBit;
|
||||
else
|
||||
buf[bufIndex] &= ~theBit;
|
||||
} else if (val->dataType == VAL_BITSTRING) {
|
||||
bitString = (byte *)val->value;
|
||||
bitLength = *bitString++;
|
||||
for (j=0; j < bitLength && i+j <
|
||||
aField->dimension; ++j) {
|
||||
bufIndex = offset + ((i+j+bitOffset)>>3);
|
||||
theBit = 1 << (7 - ((i+j+bitOffset)&7));
|
||||
if ((bitString[j>>3] >> (7-(j&7))) & 1)
|
||||
buf[bufIndex] |= theBit;
|
||||
else
|
||||
buf[bufIndex] &= ~theBit;
|
||||
}
|
||||
for (i+=bitLength; i<aField->dimension; ++i) {
|
||||
bufIndex = offset + ((i+bitOffset)>>3);
|
||||
theBit = 1 << (7 - ((i+bitOffset)&7));
|
||||
buf[bufIndex] &= ~theBit;
|
||||
}
|
||||
} else
|
||||
error("invalid data type for bit field\n");
|
||||
freeValue(val);
|
||||
}
|
||||
}
|
||||
if (data != NULL)
|
||||
error("too many initialization values\n");
|
||||
}
|
||||
|
||||
void
|
||||
fillPrototype(buf, fields, class)
|
||||
byte *buf;
|
||||
fieldList *fields;
|
||||
int class;
|
||||
{
|
||||
while (fields != NULL) {
|
||||
fillField(buf, fields->field->initValues, fields->field,
|
||||
nextIntValue, nextStringValue, nextValue);
|
||||
fields = fields->nextField;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fillProperty(buf, prop, fields, class)
|
||||
byte *buf;
|
||||
property *prop;
|
||||
fieldList *fields;
|
||||
int class;
|
||||
{
|
||||
while (fields != NULL) {
|
||||
if (fields->field->name == prop->fieldName) {
|
||||
fillField(buf, prop->data, fields->field,
|
||||
nextIntValue, nextStringValue, nextValue);
|
||||
return;
|
||||
} else {
|
||||
fields = fields->nextField;
|
||||
}
|
||||
}
|
||||
if (class > 1)
|
||||
fillProperty(buf, prop, classDefs[0]->fields, -1);
|
||||
else
|
||||
error("no match for field '%s'\n", prop->fieldName->name);
|
||||
}
|
||||
|
||||
void
|
||||
fillData(buf, fields, properties, class)
|
||||
byte *buf;
|
||||
fieldList *fields;
|
||||
propertyList *properties;
|
||||
int class;
|
||||
{
|
||||
while (properties != NULL) {
|
||||
fillProperty(buf, properties->property, fields, class);
|
||||
properties = properties->nextProp;
|
||||
}
|
||||
}
|
||||
|
||||
object *
|
||||
initObject(class, globalId)
|
||||
int class;
|
||||
int globalId;
|
||||
{
|
||||
object *result;
|
||||
objectList *buildObjectList();
|
||||
int i;
|
||||
|
||||
if (indirectPass == 1) {
|
||||
if (class == CLASS_REGION)
|
||||
indirTable[indirRegion].region = globalId;
|
||||
result = NULL;
|
||||
} else {
|
||||
result = typeAlloc(object);
|
||||
result->class = class;
|
||||
result->stateVector = byteAlloc(classDefs[class+1]->size);
|
||||
for (i=0; i<classDefs[class+1]->size; ++i)
|
||||
result->stateVector[i] = classDefs[class+1]->prototype[i];
|
||||
if (class > 1)
|
||||
fillLong(result->stateVector, 4, class);
|
||||
fillLong(result->stateVector, 0, globalId);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
object *
|
||||
generateObject(class, tail)
|
||||
int class;
|
||||
objectTail *tail;
|
||||
{
|
||||
value *val;
|
||||
int globalId;
|
||||
object *result;
|
||||
|
||||
if (tail->idExpr == NULL || indirFile != NULL) {
|
||||
globalId = -globalIdCounter++;
|
||||
} else {
|
||||
val = evaluate(tail->idExpr);
|
||||
if (!isInteger(val) || val->value <= 0) {
|
||||
error("illegal global id number\n");
|
||||
return(NULL);
|
||||
}
|
||||
globalId = val->value;
|
||||
freeValue(val);
|
||||
}
|
||||
result = initObject(class, globalId);
|
||||
if (indirectPass != 1)
|
||||
fillData(result->stateVector, classDefs[class+1]->fields,
|
||||
tail->properties, class);
|
||||
return(result);
|
||||
}
|
||||
|
||||
void
|
||||
outputRawObject(obj)
|
||||
object *obj;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (obj == NULL)
|
||||
return;
|
||||
fprintf(rawFile, "/%d ", obj->class);
|
||||
for (i=0; i<classDefs[obj->class+1]->size; ++i) {
|
||||
if ((i & 31) == 31)
|
||||
fprintf(rawFile, "\\\n");
|
||||
fprintf(rawFile, "%02x", obj->stateVector[i]);
|
||||
}
|
||||
fprintf(rawFile, "\n");
|
||||
}
|
||||
|
||||
int
|
||||
fieldCode(ftype)
|
||||
fieldType ftype;
|
||||
{
|
||||
if (ftype == FIELD_REGID)
|
||||
return(0);
|
||||
else if (ftype == FIELD_AVAID)
|
||||
return(1);
|
||||
else if (ftype == FIELD_OBJID)
|
||||
return(2);
|
||||
else
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int
|
||||
relativeId(id, contnum)
|
||||
int id;
|
||||
int contnum;
|
||||
{
|
||||
char scratchName[15];
|
||||
symbol *scratchSymbol;
|
||||
symbol *lookupSymbol();
|
||||
|
||||
sprintf(scratchName, "%c_%d", contCode(contnum), id);
|
||||
scratchSymbol = lookupSymbol(scratchName);
|
||||
if (scratchSymbol->type != VARIABLE_SYM) {
|
||||
if (id < -1000 || 0 < id) {
|
||||
error("undefined %c %d\n", contCode(contnum), id);
|
||||
return(0);
|
||||
} else
|
||||
return(id);
|
||||
} else
|
||||
return(scratchSymbol->def.value->value);
|
||||
}
|
||||
|
||||
void
|
||||
shiftField(aField, buf, adjust)
|
||||
field *aField;
|
||||
byte *buf;
|
||||
int adjust;
|
||||
{
|
||||
int i;
|
||||
int offset;
|
||||
int val;
|
||||
|
||||
offset = aField->offset & 0x3FFF;
|
||||
for (i=0; i<aField->dimension; ++i) {
|
||||
if (aField->type == FIELD_ENTITY) {
|
||||
val = getLong(buf, offset + 6*i);
|
||||
if (val < -1000)
|
||||
fillLong(buf, offset + 6*i, val - adjust);
|
||||
else if (assignRelativeIds)
|
||||
fillLong(buf, offset + 6*i,
|
||||
relativeId(val, getWord(buf, offset +
|
||||
6*i + 4)));
|
||||
} else if (aField->type == FIELD_AVAID || aField->type ==
|
||||
FIELD_OBJID || aField->type == FIELD_REGID) {
|
||||
val = getLong(buf, offset + 4*i);
|
||||
if (val < -1000)
|
||||
fillLong(buf, offset + 4*i, val - adjust);
|
||||
else if (assignRelativeIds)
|
||||
fillLong(buf, offset + 4*i, relativeId(val,
|
||||
fieldCode(aField->type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
shiftRelativeGlobalIds(obj, adjust)
|
||||
object *obj;
|
||||
int adjust;
|
||||
{
|
||||
fieldList *fields;
|
||||
|
||||
if (obj->class > 1) {
|
||||
fields = classDefs[0]->fields;
|
||||
while (fields != NULL) {
|
||||
shiftField(fields->field, obj->stateVector, adjust);
|
||||
fields = fields->nextField;
|
||||
}
|
||||
}
|
||||
fields = classDefs[obj->class+1]->fields;
|
||||
while (fields != NULL) {
|
||||
shiftField(fields->field, obj->stateVector, adjust);
|
||||
fields = fields->nextField;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
generateScratchId(class, id, relativeId)
|
||||
int class;
|
||||
int id;
|
||||
int relativeId;
|
||||
{
|
||||
char scratchName[15];
|
||||
symbol *scratchSymbol;
|
||||
valueType vtype;
|
||||
value *buildValue();
|
||||
symbol *lookupSymbol();
|
||||
|
||||
sprintf(scratchName, "%c_%d", contCode(class), id);
|
||||
scratchSymbol = lookupSymbol(scratchName);
|
||||
scratchSymbol->type = VARIABLE_SYM;
|
||||
if (class == 0)
|
||||
vtype = VAL_REGION;
|
||||
else if (class == 1)
|
||||
vtype = VAL_AVATAR;
|
||||
else
|
||||
vtype = VAL_OBJECT;
|
||||
scratchSymbol->def.value = buildValue(vtype, relativeId);
|
||||
}
|
||||
|
||||
void
|
||||
executeRawline(obj)
|
||||
object *obj;
|
||||
{
|
||||
if (assignRelativeIds)
|
||||
generateScratchId(obj->class, getLong(obj->stateVector, 0),
|
||||
-1001 - objectCount);
|
||||
shiftRelativeGlobalIds(obj, objectCount - rawCount++);
|
||||
if (objectCount < MAXNOID)
|
||||
noidArray[objectCount++] = obj;
|
||||
}
|
||||
|
||||
void
|
||||
freeObjectTail(tail)
|
||||
objectTail *tail;
|
||||
{
|
||||
propertyList *properties;
|
||||
propertyList *oldProperties;
|
||||
exprList *expr;
|
||||
exprList *oldExpr;
|
||||
|
||||
properties = tail->properties;
|
||||
while (properties != NULL) {
|
||||
expr = properties->property->data;
|
||||
while (expr != NULL) {
|
||||
if (indirectPass == 1)
|
||||
freeExpr(expr->expr);
|
||||
oldExpr = expr;
|
||||
expr = expr->nextExpr;
|
||||
free(oldExpr);
|
||||
}
|
||||
free(properties->property);
|
||||
oldProperties = properties;
|
||||
properties = properties->nextProp;
|
||||
free(oldProperties);
|
||||
}
|
||||
free(tail);
|
||||
}
|
||||
|
||||
void
|
||||
executeUse(className, tagName, tail)
|
||||
symbol *className;
|
||||
symbol *tagName;
|
||||
objectTail *tail;
|
||||
{
|
||||
object *ultimate;
|
||||
objectStub *buildObjectStub();
|
||||
|
||||
if (className->type != CLASS_SYM)
|
||||
error("non-class identifier %s used for class name\n",
|
||||
className->name);
|
||||
else {
|
||||
ultimate = generateObject(className->def.class, tail);
|
||||
freeObjectTail(tail);
|
||||
if (ultimate != NULL && tagName != NULL) {
|
||||
if (ultimate->class == 0)
|
||||
globalIdAdjustment = 0;
|
||||
if (tagName->type == OBJECT_SYM)
|
||||
free(tagName->def.object);
|
||||
else if(tagName->type == VARIABLE_SYM)
|
||||
freeValue(tagName->def.value);
|
||||
tagName->type = OBJECT_SYM;
|
||||
tagName->def.object = buildObjectStub(ultimate);
|
||||
}
|
||||
/*#ifndef FRED*/
|
||||
if (ultimate != NULL) {
|
||||
if (ultimate->class == CLASS_DOOR ||
|
||||
ultimate->class == CLASS_BUILDING)
|
||||
sortObjects = TRUE;
|
||||
else if (ultimate->class == CLASS_REGION)
|
||||
flushNoidArray();
|
||||
if (objectCount < MAXNOID && indirectPass != 1)
|
||||
noidArray[objectCount++] = ultimate;
|
||||
else if (indirectPass != 0)
|
||||
error("more than 256 objects in region\n");
|
||||
}
|
||||
/*#endif*/
|
||||
}
|
||||
}
|
||||
|
||||
cmpObjects(ob1, ob2)
|
||||
object **ob1;
|
||||
object **ob2;
|
||||
{
|
||||
int class1, class2;
|
||||
|
||||
class1 = (*ob1)->class;
|
||||
class2 = (*ob2)->class;
|
||||
if (class1 == CLASS_REGION)
|
||||
return(-1);
|
||||
else if (class2 == CLASS_REGION)
|
||||
return(1);
|
||||
else if (class1 != CLASS_DOOR && class1 != CLASS_BUILDING &&
|
||||
class2 != CLASS_DOOR && class2 != CLASS_BUILDING)
|
||||
return(0);
|
||||
else if (class1 != CLASS_DOOR && class1 != CLASS_BUILDING)
|
||||
return(1);
|
||||
else if (class2 != CLASS_DOOR && class2 != CLASS_BUILDING)
|
||||
return(-1);
|
||||
return(getLong((*ob1)->stateVector, X_OFFSET_OBJ) -
|
||||
getLong((*ob2)->stateVector, X_OFFSET_OBJ));
|
||||
}
|
||||
|
||||
flushNoidArray()
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifndef FRED
|
||||
if (indirectPass == 2) {
|
||||
for (i=0; i<objectCount; ++i)
|
||||
altNoidArray[i] = noidArray[i];
|
||||
if (sortObjects)
|
||||
qsort(altNoidArray, objectCount, sizeof(object *),
|
||||
cmpObjects);
|
||||
for (i=0; i<objectCount; ++i)
|
||||
replaceIndirectArgs(altNoidArray[i], i);
|
||||
}
|
||||
sortObjects = FALSE;
|
||||
#endif
|
||||
for (i=0; i<objectCount; ++i) {
|
||||
#ifndef FRED
|
||||
if (griFile != NULL && indirectPass != 1)
|
||||
dumpObject(noidArray[i]);
|
||||
if (rawFile != NULL && indirectPass != 1)
|
||||
outputRawObject(noidArray[i]);
|
||||
#endif
|
||||
freeObject(noidArray[i]);
|
||||
}
|
||||
objectCount = 0;
|
||||
}
|
||||
|
||||
freeObject(obj)
|
||||
object *obj;
|
||||
{
|
||||
free(obj->stateVector);
|
||||
free(obj);
|
||||
}
|
||||
|
||||
freeValue(val)
|
||||
value *val;
|
||||
{
|
||||
if (val != NULL) {
|
||||
if (val->dataType == VAL_STRING ||
|
||||
val->dataType == VAL_BITSTRING)
|
||||
free(val->value);
|
||||
free(val);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
executeDefine(classExpr, name, fields)
|
||||
expression *classExpr;
|
||||
char *name;
|
||||
fieldList *fields;
|
||||
{
|
||||
value *val;
|
||||
int class;
|
||||
symbol *symb;
|
||||
symbol *lookupSymbol();
|
||||
int size;
|
||||
|
||||
val = evaluate(classExpr);
|
||||
class = val->value;
|
||||
if (!isInteger(val))
|
||||
error("non-integer value used for class number\n");
|
||||
else if (class < -1 || MAXCLASS <= class)
|
||||
error("class value %d out of range\n", class);
|
||||
else if (classDefs[class+1] != NULL)
|
||||
error("class %d already defined\n", class);
|
||||
else {
|
||||
translate(name, ' ', '_');
|
||||
symb = lookupSymbol(name);
|
||||
symb->type = CLASS_SYM;
|
||||
symb->def.class = class;
|
||||
classDefs[class+1] = typeAlloc(classDescriptor);
|
||||
size = computeFieldOffsets(fields, class);
|
||||
classDefs[class+1]->size = size;
|
||||
classDefs[class+1]->fields = fields;
|
||||
classDefs[class+1]->className = symb;
|
||||
classDefs[class+1]->prototype = (byte *)malloc(size);
|
||||
fillPrototype(classDefs[class+1]->prototype, fields, class);
|
||||
}
|
||||
freeValue(val);
|
||||
free(name);
|
||||
}
|
||||
|
||||
int
|
||||
computeFieldOffsets(fields, class)
|
||||
fieldList *fields;
|
||||
int class;
|
||||
{
|
||||
int offset;
|
||||
int bitOffset;
|
||||
field *aField;
|
||||
|
||||
if (class > 1)
|
||||
offset = objectBase;
|
||||
else
|
||||
offset = 0;
|
||||
if (fields == NULL)
|
||||
return(offset);
|
||||
|
||||
bitOffset = 0;
|
||||
while (fields != NULL) {
|
||||
aField = fields->field;
|
||||
aField->offset = offset + (bitOffset << 14);
|
||||
|
||||
if (class == -1)
|
||||
objectBase = offset;
|
||||
|
||||
switch (aField->type) {
|
||||
Case FIELD_ENTITY:
|
||||
offset += 6 * aField->dimension;
|
||||
|
||||
Case FIELD_AVAID:
|
||||
case FIELD_BIN31:
|
||||
case FIELD_OBJID:
|
||||
case FIELD_REGID:
|
||||
case FIELD_FATWORD:
|
||||
offset += 4 * aField->dimension;
|
||||
|
||||
Case FIELD_BIN15:
|
||||
case FIELD_WORDS:
|
||||
offset += 2 * aField->dimension;
|
||||
|
||||
Case FIELD_BYTE:
|
||||
case FIELD_CHARACTER:
|
||||
offset += aField->dimension;
|
||||
|
||||
Case FIELD_VARSTRING:
|
||||
offset += aField->dimension + 2;
|
||||
|
||||
Case FIELD_BIT:
|
||||
bitOffset += aField->dimension;
|
||||
if (bitOffset > 15) {
|
||||
offset += 2 * (bitOffset >> 4);
|
||||
bitOffset -= (bitOffset & ~0xF);
|
||||
}
|
||||
}
|
||||
|
||||
if (aField->type != FIELD_BIT && bitOffset > 0) {
|
||||
bitOffset = 0;
|
||||
offset += 2;
|
||||
} else if (aField->type != FIELD_CHARACTER &&
|
||||
aField->type != FIELD_BYTE && (offset & 1) == 1)
|
||||
++offset;
|
||||
|
||||
fields = fields->nextField;
|
||||
}
|
||||
if (bitOffset > 0)
|
||||
offset += 2;
|
||||
return(offset);
|
||||
}
|
252
mamelink/griddle/expr.c
Normal file
252
mamelink/griddle/expr.c
Normal file
|
@ -0,0 +1,252 @@
|
|||
#include "y.tab.h"
|
||||
#include "griddleDefs.h"
|
||||
|
||||
value *
|
||||
integerize(val)
|
||||
value *val;
|
||||
{
|
||||
char *string;
|
||||
int i;
|
||||
value *buildNumber();
|
||||
|
||||
if (val == NULL) {
|
||||
val = buildNumber(0);
|
||||
} else if (val->dataType == VAL_UNDEFINED) {
|
||||
val->value = 0;
|
||||
val->dataType = VAL_INTEGER;
|
||||
} else if (val->dataType == VAL_STRING) {
|
||||
string = (char *)val->value;
|
||||
val->value = 0;
|
||||
for (i=0; i < 4 && string[i] != '\0'; ++i)
|
||||
val->value = val->value * 256 + string[i];
|
||||
val->dataType = VAL_INTEGER;
|
||||
} else if (val->dataType == VAL_BITSTRING) {
|
||||
/* do something */
|
||||
val->value = 0;
|
||||
val->dataType = VAL_INTEGER;
|
||||
}
|
||||
return(val);
|
||||
}
|
||||
|
||||
boolean
|
||||
isInteger(val)
|
||||
value *val;
|
||||
{
|
||||
return(val != NULL &&
|
||||
(val->dataType == VAL_INTEGER || val->dataType == VAL_AVATAR ||
|
||||
val->dataType == VAL_OBJECT || val->dataType == VAL_REGION));
|
||||
}
|
||||
|
||||
boolean
|
||||
isString(val)
|
||||
value *val;
|
||||
{
|
||||
return(val->dataType == VAL_STRING);
|
||||
}
|
||||
|
||||
value *
|
||||
evaluate(expr)
|
||||
expression *expr;
|
||||
{
|
||||
value *result;
|
||||
value *evaluateName();
|
||||
value *evaluateUnop();
|
||||
value *evaluateBin();
|
||||
value *buildNumber();
|
||||
value *buildString();
|
||||
value *buildBitString();
|
||||
|
||||
switch (expr->type) {
|
||||
Case ID_EXPR:
|
||||
result = evaluateName(expr->part1);
|
||||
Case NUM_EXPR:
|
||||
result = buildNumber((int) expr->part1);
|
||||
Case EXPR_EXPR:
|
||||
result = evaluate(expr->part1);
|
||||
Case UNOP_EXPR:
|
||||
result = evaluateUnop(expr->part1, evaluate(expr->part2));
|
||||
Case BIN_EXPR:
|
||||
result = evaluateBin(evaluate(expr->part1), expr->part2,
|
||||
evaluate(expr->part3));
|
||||
Case STRING_EXPR:
|
||||
result = buildString((char *) expr->part1);
|
||||
Case BITSTRING_EXPR:
|
||||
result = buildBitString((byte *) expr->part1);
|
||||
Default:
|
||||
printf("bad expr type leaked thru!\n");
|
||||
exit(1);
|
||||
}
|
||||
free(expr);
|
||||
return(result);
|
||||
}
|
||||
|
||||
void
|
||||
freeExpr(expr)
|
||||
expression *expr;
|
||||
{
|
||||
switch (expr->type) {
|
||||
Case EXPR_EXPR:
|
||||
freeExpr(expr->part1);
|
||||
Case UNOP_EXPR:
|
||||
freeExpr(expr->part2);
|
||||
Case BIN_EXPR:
|
||||
freeExpr(expr->part1);
|
||||
freeExpr(expr->part3);
|
||||
Case STRING_EXPR:
|
||||
free(expr->part1);
|
||||
Case BITSTRING_EXPR:
|
||||
free(expr->part1);
|
||||
}
|
||||
free(expr);
|
||||
}
|
||||
|
||||
value *
|
||||
evaluateUnop(oper, opnd)
|
||||
int oper;
|
||||
value *opnd;
|
||||
{
|
||||
opnd = integerize(opnd);
|
||||
switch(oper) {
|
||||
Case NOT:
|
||||
opnd->value = ~opnd->value;
|
||||
|
||||
Case UMINUS:
|
||||
opnd->value = -opnd->value;
|
||||
|
||||
Case A:
|
||||
if (opnd->dataType == VAL_OBJECT ||
|
||||
opnd->dataType == VAL_REGION)
|
||||
error("incompatible type coercion\n");
|
||||
opnd->dataType = VAL_AVATAR;
|
||||
|
||||
Case O:
|
||||
if (opnd->dataType == VAL_AVATAR ||
|
||||
opnd->dataType == VAL_REGION)
|
||||
error("incompatible type coercion\n");
|
||||
opnd->dataType = VAL_OBJECT;
|
||||
|
||||
Case R:
|
||||
if (opnd->dataType == VAL_OBJECT ||
|
||||
opnd->dataType == VAL_AVATAR)
|
||||
error("incompatible type coercion\n");
|
||||
opnd->dataType = VAL_REGION;
|
||||
|
||||
Default:
|
||||
printf("bad unop leaked thru!\n");
|
||||
exit(1);
|
||||
}
|
||||
return(opnd);
|
||||
}
|
||||
|
||||
value *
|
||||
evaluateBin(opnd1, oper, opnd2)
|
||||
value *opnd1;
|
||||
int oper;
|
||||
value *opnd2;
|
||||
{
|
||||
opnd1 = integerize(opnd1);
|
||||
opnd2 = integerize(opnd2);
|
||||
switch(oper) {
|
||||
case ADD:
|
||||
opnd1->value += opnd2->value;
|
||||
break;
|
||||
case SUB:
|
||||
opnd1->value -= opnd2->value;
|
||||
break;
|
||||
case MUL:
|
||||
opnd1->value *= opnd2->value;
|
||||
break;
|
||||
case DIV:
|
||||
opnd1->value /= opnd2->value;
|
||||
break;
|
||||
case MOD:
|
||||
opnd1->value %= opnd2->value;
|
||||
break;
|
||||
case AND:
|
||||
opnd1->value &= opnd2->value;
|
||||
break;
|
||||
case OR:
|
||||
opnd1->value |= opnd2->value;
|
||||
break;
|
||||
case XOR:
|
||||
opnd1->value ^= opnd2->value;
|
||||
break;
|
||||
default:
|
||||
printf("bad binop leaked thru!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (opnd1->dataType != opnd2->dataType) {
|
||||
if (opnd1->dataType == VAL_INTEGER)
|
||||
opnd1->dataType = opnd2->dataType;
|
||||
else if (opnd2->dataType != VAL_INTEGER)
|
||||
error("incompatible type combination");
|
||||
}
|
||||
free(opnd2);
|
||||
return(opnd1);
|
||||
}
|
||||
|
||||
#ifdef FRED
|
||||
value *
|
||||
valueFromName(name)
|
||||
char *name;
|
||||
{
|
||||
int len;
|
||||
int i;
|
||||
int result;
|
||||
value *buildValue();
|
||||
|
||||
if ((len = strlen(name)) < 3 || name[1] != '_')
|
||||
return(NULL);
|
||||
result = 0;
|
||||
for (i=2; i<len; ++i)
|
||||
if ('0' <= name[i] && name[i] <= '9')
|
||||
result = result * 10 + name[i] - '0';
|
||||
else
|
||||
return(NULL);
|
||||
if (name[0] == 'r')
|
||||
return(buildValue(VAL_REGION, result));
|
||||
else if (name[0] == 'o')
|
||||
return(buildValue(VAL_OBJECT, result));
|
||||
else if (name[0] == 'a')
|
||||
return(buildValue(VAL_AVATAR, result));
|
||||
else
|
||||
return(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
value *
|
||||
evaluateName(name)
|
||||
symbol *name;
|
||||
{
|
||||
value *buildNumber();
|
||||
value *buildValue();
|
||||
value *result;
|
||||
|
||||
switch(name->type) {
|
||||
case VARIABLE_SYM:
|
||||
return(buildValue(name->def.value->dataType,
|
||||
name->def.value->value));
|
||||
case MACRO_SYM:
|
||||
return(evaluate(name->def.expr));
|
||||
case OBJECT_SYM:
|
||||
result = buildNumber(name->def.object->id);
|
||||
if (name->def.object->class == 0)
|
||||
result->dataType = VAL_REGION;
|
||||
else if (name->def.object->class == 1)
|
||||
result->dataType = VAL_AVATAR;
|
||||
else
|
||||
result->dataType = VAL_OBJECT;
|
||||
return(result);
|
||||
case NON_SYM:
|
||||
#ifdef FRED
|
||||
if ((result = valueFromName(name->name)) != NULL)
|
||||
return(result);
|
||||
#endif
|
||||
printf("symbol %s undefined\n", name->name);
|
||||
return(buildNumber(0));
|
||||
|
||||
default:
|
||||
printf("bad symbol type leaked thru!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
900
mamelink/griddle/fred.c
Normal file
900
mamelink/griddle/fred.c
Normal file
|
@ -0,0 +1,900 @@
|
|||
#include <curses.h>
|
||||
#include <signal.h>
|
||||
#include "griddleDefs.h"
|
||||
#include "prot.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
static int selectedField = 0;
|
||||
static int selectedPath = 0;
|
||||
static int editX = 0;
|
||||
static int editY = 0;
|
||||
static char *editPath;
|
||||
static field *editField = NULL;
|
||||
static boolean changedFlag = FALSE;
|
||||
|
||||
static char paths[10][80];
|
||||
static char pathFileName[80];
|
||||
|
||||
int fredStats[128];
|
||||
|
||||
typedef struct {
|
||||
char commandKey;
|
||||
char *echoName;
|
||||
boolean (*commandFunction)();
|
||||
char *helpInfo;
|
||||
} command;
|
||||
|
||||
void echoLine();
|
||||
void lineError();
|
||||
boolean getString();
|
||||
boolean processCommand();
|
||||
void displayOneObject();
|
||||
|
||||
boolean saveGriddle(), initC64editor(), loadRegion(), quit(), saveRaw(), sh();
|
||||
boolean refreshScreen(), showNoids(), displayObject(), incDisplayObject();
|
||||
boolean decDisplayObject(), createObject(), help(), touch(), undeleteObject();
|
||||
boolean deleteObject(), foreground(), background(), incX_4(), decX_4();
|
||||
boolean incY_1(), decY_1(), incY_10(), decY_10(), zeroGrState(), incGrState();
|
||||
boolean toggleOrient(), editObject(), nightMode(), walkto(), showFlatTypes();
|
||||
boolean eraseBackground(), incPattern(), decPattern(), flatChange();
|
||||
boolean twinObject(), peekContainer(), changeContainer(), trapEdit();
|
||||
boolean borderToggle(), containerOffsetRight(), containerOffsetLeft();
|
||||
boolean containerOffsetUp(), containerOffsetDown(), changeHold(), pauseFred();
|
||||
boolean editPathlist(), displayPathlist();
|
||||
|
||||
command commandTable[] = {
|
||||
'b', "background object", background, "move object to background",
|
||||
'B', "background display suppression", eraseBackground,
|
||||
"display without background",
|
||||
ctrl(B), "border/unborder trapezoid trap", borderToggle,
|
||||
"border/unborder trapezoid",
|
||||
'c', "create new object", createObject, "create a new object",
|
||||
'C', "container peek", peekContainer, "look inside container",
|
||||
'd', "display object", displayObject, "display an object",
|
||||
'D', "drop into container", changeContainer,
|
||||
"drop object into container",
|
||||
ctrl(D), "display pathlist", displayPathlist,
|
||||
"display current pathlist",
|
||||
'e', "edit object", editObject, "edit an object's state info",
|
||||
'E', "edit trapezoid", trapEdit, "edit a trapezoid's corner info",
|
||||
'f', "foreground object", foreground, "move object to foreground",
|
||||
'F', "flat type change", flatChange, "change type of flat",
|
||||
'g', "griddle format save", saveGriddle, "save in griddle format",
|
||||
'G', "show flat types", showFlatTypes, "show flat types",
|
||||
'h', "help", help, "display help info",
|
||||
'H', "offset left", containerOffsetLeft, NULL,
|
||||
'i', "initialize region editor", initC64editor, "init Reno",
|
||||
'I', "change how held", changeHold, NULL,
|
||||
'J', "offset up", containerOffsetUp, NULL,
|
||||
'K', "offset down", containerOffsetDown, NULL,
|
||||
'L', "offset right", containerOffsetRight, NULL,
|
||||
'n', "night mode", nightMode, "switch display to night mode",
|
||||
'o', "object noid list", showNoids, "show noids and classes",
|
||||
'O', "orientation flip", toggleOrient, "toggle object's orientation",
|
||||
'p', "inc color/pattern", incPattern, "inc object's color/pattern",
|
||||
'P', "dec color/pattern", decPattern, "dec object's color/pattern",
|
||||
ctrl(P), "path list edit", editPathlist, "edit path list",
|
||||
'q', "quit", quit, "exit Fred",
|
||||
'r', "read region from file", loadRegion, "read region from a file",
|
||||
's', "set grState to 0", zeroGrState, "set object's grState to 0",
|
||||
'S', "inc grState", incGrState, "inc object's grState",
|
||||
't', "touch object under cursor", touch, "touch object under cursor",
|
||||
'T', "twin object", twinObject, "twin object",
|
||||
'u', "undelete deleted object", undeleteObject,
|
||||
"undo object deletion",
|
||||
'w', "walk to indicated object", walkto, "walk avatar to object",
|
||||
'x', "delete object", deleteObject, "delete an object",
|
||||
'z', "raw format save", saveRaw, "save in raw format",
|
||||
'+', "display object", incDisplayObject, "inc display noid",
|
||||
'-', "display object", decDisplayObject, "dec display noid",
|
||||
'!', "unix command", sh, "execute a Unix command",
|
||||
'.', "inc X", incX_4, "inc object's X coordinate",
|
||||
',', "dec X", decX_4, "dec object's X coordinate",
|
||||
'?', "inc Y", incY_1, "inc object's Y coordinate",
|
||||
'/', "dec Y", decY_1, "dec object's Y coordinate",
|
||||
'>', "inc Y by 10", incY_10, "inc object's Y coordinate by 10",
|
||||
'<', "dec Y by 10", decY_10, "dec object's Y coordinate by 10",
|
||||
'\r', "refresh Fred screen", refreshScreen, "refresh screen",
|
||||
ctrl(Z), "pause Fred", pauseFred, "pause Fred",
|
||||
'\0', NULL, NULL, NULL
|
||||
};
|
||||
|
||||
extern char *getenv();
|
||||
|
||||
/* flags */
|
||||
#define NCARDS 3
|
||||
int card = 0;
|
||||
int port = 0;
|
||||
|
||||
void
|
||||
c64_override_command(cmd)
|
||||
byte cmd;
|
||||
{
|
||||
if (!testMode) {
|
||||
down(&cmd, (word) 1, KEYBOARD_OVERRIDE);
|
||||
Cont();
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
c64_key_command(cmd)
|
||||
byte cmd;
|
||||
{
|
||||
byte buf;
|
||||
|
||||
buf = cmd;
|
||||
if (!testMode) {
|
||||
down(&buf, (word) 1, KEYBOARD_KEYPRESS);
|
||||
Cont();
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
c64_touch_command(arg)
|
||||
byte arg;
|
||||
{
|
||||
byte buf;
|
||||
|
||||
buf = arg;
|
||||
if (!testMode) {
|
||||
down(&buf, (word) 1, TOUCH_SLOT);
|
||||
Cont();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
readFredStats()
|
||||
{
|
||||
FILE *statFyle;
|
||||
int i;
|
||||
|
||||
if ((statFyle = fopen("/u0/habitat/fredStats", "r")) != NULL) {
|
||||
for (i=0; i<128; ++i)
|
||||
fredStats[i] = getw(statFyle);
|
||||
fclose(statFyle);
|
||||
}
|
||||
if (statFyle == NULL || feof(statFyle)) {
|
||||
for (i=0; i<128; ++i)
|
||||
fredStats[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
writeFredStats()
|
||||
{
|
||||
FILE *statFyle;
|
||||
int i;
|
||||
|
||||
if ((statFyle = fopen("/u0/habitat/fredStats", "w")) != NULL) {
|
||||
for (i=0; i<128; ++i)
|
||||
putw(fredStats[i], statFyle);
|
||||
fclose(statFyle);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
touchObject()
|
||||
{
|
||||
char buf;
|
||||
|
||||
if (!testMode) {
|
||||
c64_key_command('t');
|
||||
up(&buf, (word) 1, TOUCHED_OBJECT);
|
||||
Cont();
|
||||
return(buf);
|
||||
} else
|
||||
return(displayNoid);
|
||||
}
|
||||
|
||||
boolean
|
||||
touch()
|
||||
{
|
||||
displayNoid = touchObject();
|
||||
displayOneObject(displayNoid);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
help()
|
||||
{
|
||||
int i;
|
||||
int y, x;
|
||||
int line, col;
|
||||
|
||||
line = 1;
|
||||
col = 0;
|
||||
getyx(curscr, y, x);
|
||||
clearDisplay();
|
||||
for (i=0; commandTable[i].commandKey!='\0'; ++i) {
|
||||
if (commandTable[i].helpInfo != NULL) {
|
||||
mvprintw(line, col, "%s -- %s",
|
||||
keyName(commandTable[i].commandKey),
|
||||
commandTable[i].helpInfo);
|
||||
nextlc(line, col, 40);
|
||||
}
|
||||
}
|
||||
move(y, x);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
displayField(line, col, aField, buf, highlight)
|
||||
int line;
|
||||
int col;
|
||||
field *aField;
|
||||
byte *buf;
|
||||
boolean highlight;
|
||||
{
|
||||
char str[512];
|
||||
|
||||
if (fieldString(aField, buf, str)) {
|
||||
if (highlight) {
|
||||
editX = col;
|
||||
editY = line;
|
||||
editField = aField;
|
||||
}
|
||||
mvaddstr(line, col, " ");
|
||||
if (highlight)
|
||||
standout();
|
||||
addstr(str);
|
||||
if (highlight)
|
||||
standend();
|
||||
return(TRUE);
|
||||
} else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
int
|
||||
displayFieldList(fields, buf, lineptr, colptr, fieldNum)
|
||||
fieldList *fields;
|
||||
byte *buf;
|
||||
int *lineptr;
|
||||
int *colptr;
|
||||
int fieldNum;
|
||||
{
|
||||
while (fields != NULL) {
|
||||
if (displayField(*lineptr, *colptr, fields->field, buf,
|
||||
fieldNum == selectedField)) {
|
||||
nextlc(*lineptr, *colptr, 40);
|
||||
++fieldNum;
|
||||
}
|
||||
fields = fields->nextField;
|
||||
}
|
||||
return(fieldNum);
|
||||
}
|
||||
|
||||
void
|
||||
revalueField(firstc, buf)
|
||||
char firstc;
|
||||
byte *buf;
|
||||
{
|
||||
ungetch(firstc);
|
||||
fredModeLexingOn();
|
||||
fillFieldPrompt(editY, editX, editField, buf, TRUE);
|
||||
fredModeLexingOff();
|
||||
}
|
||||
|
||||
bool
|
||||
showObject(noid)
|
||||
int noid;
|
||||
{
|
||||
object *obj;
|
||||
int line, col;
|
||||
int y, x;
|
||||
int fieldNum;
|
||||
|
||||
line = 1;
|
||||
col = 0;
|
||||
fieldNum = 1;
|
||||
obj = noidArray[noid];
|
||||
getyx(curscr, y, x);
|
||||
clearDisplay();
|
||||
if (obj->class > 1)
|
||||
fieldNum = displayFieldList(classDefs[0]->fields,
|
||||
obj->stateVector, &line, &col, fieldNum);
|
||||
fieldNum = displayFieldList(classDefs[obj->class+1]->fields,
|
||||
obj->stateVector, &line, &col, fieldNum);
|
||||
move(y, x);
|
||||
refresh();
|
||||
return(fieldNum - 1 == selectedField);
|
||||
}
|
||||
|
||||
void
|
||||
editOneObject(noid)
|
||||
int noid;
|
||||
{
|
||||
char c;
|
||||
boolean lastField;
|
||||
|
||||
showObject(noid);
|
||||
selectedField = 1;
|
||||
changedFlag = FALSE;
|
||||
do {
|
||||
lastField = showObject(noid);
|
||||
c = mygetch();
|
||||
if (c == DEL)
|
||||
break;
|
||||
else if (c == '\b') {
|
||||
selectedField = selectedField < 2 ?
|
||||
0 : selectedField - 2;
|
||||
lastField = FALSE;
|
||||
} else if (c != '\r' && c != '\n' && c != ' ')
|
||||
revalueField(c, noidArray[noid]->stateVector);
|
||||
++selectedField;
|
||||
} while (!lastField);
|
||||
selectedField = 0;
|
||||
showObject(noid);
|
||||
}
|
||||
|
||||
boolean
|
||||
editObject()
|
||||
{
|
||||
int y, x;
|
||||
|
||||
echoLine("editing object %d (%s)", displayNoid,
|
||||
classDefs[noidArray[displayNoid]->class+1]->className->name);
|
||||
getyx(curscr, y, x);
|
||||
editOneObject(displayNoid);
|
||||
if (changedFlag)
|
||||
uploadRegion();
|
||||
move(y, x);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
displayOneObject(noid)
|
||||
int noid;
|
||||
{
|
||||
echoLine("object %d (%s)", noid,
|
||||
classDefs[noidArray[noid]->class+1]->className->name);
|
||||
showObject(noid);
|
||||
}
|
||||
|
||||
boolean
|
||||
displayObject()
|
||||
{
|
||||
int noid;
|
||||
|
||||
noid = promptInt("noid #", displayNoid);
|
||||
if (noid == -1)
|
||||
echoLine("aborted");
|
||||
else if (noid < 0 || MAXNOID <= noid)
|
||||
lineError("noid out of range");
|
||||
else if (noidArray[noid] == NULL)
|
||||
lineError("there is no object #%d", noid);
|
||||
else {
|
||||
displayNoid = noid;
|
||||
if (noid != 0)
|
||||
c64_touch_command(noid);
|
||||
displayOneObject(noid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
incDisplayObject()
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
if (displayNoid == MAXNOID - 1) displayNoid = -1;
|
||||
while (noidArray[++displayNoid] == NULL && ++count < MAXNOID)
|
||||
if (displayNoid == MAXNOID - 1) displayNoid = -1;
|
||||
if (noidArray[displayNoid] != NULL) {
|
||||
if (displayNoid != 0)
|
||||
c64_touch_command(displayNoid);
|
||||
displayOneObject(displayNoid);
|
||||
} else
|
||||
lineError("no objects to display!");
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
decDisplayObject()
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
if (displayNoid == 0) displayNoid = MAXNOID;
|
||||
while (noidArray[--displayNoid] == NULL && ++count < MAXNOID)
|
||||
if (displayNoid == 0) displayNoid = MAXNOID;
|
||||
if (noidArray[displayNoid] != NULL) {
|
||||
if (displayNoid != 0)
|
||||
c64_touch_command(displayNoid);
|
||||
displayOneObject(displayNoid);
|
||||
} else
|
||||
lineError("no objects to display!");
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
deleteObject()
|
||||
{
|
||||
if (displayNoid == 0)
|
||||
lineError("can't delete the region!");
|
||||
else {
|
||||
if (undeleteBuffer != NULL)
|
||||
freeObject(undeleteBuffer);
|
||||
undeleteBuffer = noidArray[displayNoid];
|
||||
noidArray[displayNoid] = NULL;
|
||||
if (displayNoid == objectCount)
|
||||
--objectCount;
|
||||
echoLine("object %d is gone", displayNoid);
|
||||
incDisplayObject();
|
||||
uploadRegion();
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
undeleteObject()
|
||||
{
|
||||
int noid;
|
||||
|
||||
if (undeleteBuffer == NULL)
|
||||
lineError("no deleted object to restore");
|
||||
else {
|
||||
noid = nextFreeNoid();
|
||||
noidArray[noid] = undeleteBuffer;
|
||||
undeleteBuffer = NULL;
|
||||
echoLine("object restored to noid %d", noid);
|
||||
uploadRegion();
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
fillFieldPrompt(line, col, aField, buf, editMode)
|
||||
int line;
|
||||
int col;
|
||||
field *aField;
|
||||
byte *buf;
|
||||
boolean editMode;
|
||||
{
|
||||
char temp[80];
|
||||
value *parseBit();
|
||||
value *parseInt();
|
||||
char *parseString();
|
||||
|
||||
if (aField->invisible)
|
||||
return(FALSE);
|
||||
|
||||
fieldPrompt(line, col, aField, buf, editMode);
|
||||
if (mygetstr(temp) && temp[0] != '\0') {
|
||||
fillField(buf, temp, aField, parseInt, parseString, parseBit);
|
||||
changedFlag = TRUE;
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
fillDataPrompt(lineptr, colptr, buf, fields, class)
|
||||
int *lineptr;
|
||||
int *colptr;
|
||||
byte *buf;
|
||||
fieldList *fields;
|
||||
int class;
|
||||
{
|
||||
fredModeLexingOn();
|
||||
while (fields != NULL) {
|
||||
if (fillFieldPrompt(*lineptr, *colptr, fields->field, buf,
|
||||
FALSE))
|
||||
nextlc(*lineptr, *colptr, 40);
|
||||
fields = fields->nextField;
|
||||
}
|
||||
fredModeLexingOff();
|
||||
}
|
||||
|
||||
void
|
||||
generateFredObject(class, twinFlag)
|
||||
int class;
|
||||
boolean twinFlag;
|
||||
{
|
||||
object *obj;
|
||||
object *initObject();
|
||||
int noid;
|
||||
int i;
|
||||
|
||||
obj = initObject(class, -globalIdCounter++);
|
||||
if (twinFlag)
|
||||
for (i=4; i<classDefs[class+1]->size; ++i)
|
||||
obj->stateVector[i] =
|
||||
noidArray[displayNoid]->stateVector[i];
|
||||
noid = nextFreeNoid();
|
||||
displayNoid = noid;
|
||||
noidArray[noid] = obj;
|
||||
clearDisplay();
|
||||
if (twinFlag)
|
||||
displayOneObject(noid);
|
||||
else
|
||||
editOneObject(noid);
|
||||
}
|
||||
|
||||
boolean
|
||||
createObject()
|
||||
{
|
||||
int class;
|
||||
void displayRegion();
|
||||
|
||||
class = promptInt("-- class", previousClass);
|
||||
if (class == -1)
|
||||
echoLine("aborted");
|
||||
else if (class < 1 || MAXCLASS <= class)
|
||||
lineError("class value %d is out of range", class);
|
||||
else {
|
||||
echoLine("creating class %d (%s)", class,
|
||||
classDefs[class+1]->className->name);
|
||||
previousClass = class;
|
||||
generateFredObject(class, FALSE);
|
||||
uploadRegion();
|
||||
echoLine("created object %d, class %d (%s)", displayNoid,
|
||||
class, classDefs[class+1]->className->name);
|
||||
c64_touch_command(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
twinObject()
|
||||
{
|
||||
int class;
|
||||
|
||||
if (displayNoid == 0)
|
||||
lineError("can't twin region");
|
||||
else {
|
||||
class = noidArray[displayNoid]->class;
|
||||
previousClass = class;
|
||||
generateFredObject(class, TRUE);
|
||||
/* announceObject(displayNoid, class);*/
|
||||
uploadRegion();
|
||||
echoLine("created object %d, class %d (%s)", displayNoid,
|
||||
class, classDefs[class+1]->className->name);
|
||||
c64_touch_command(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
showNoids()
|
||||
{
|
||||
int line, col;
|
||||
int y, x;
|
||||
int i;
|
||||
|
||||
line = 1;
|
||||
col = 0;
|
||||
getyx(curscr, y, x);
|
||||
clearDisplay();
|
||||
for (i=0; i<objectCount; ++i)
|
||||
if (noidArray[i] != NULL) {
|
||||
mvprintw(line, col, "%3d %s", i,
|
||||
classDefs[noidArray[i]->class+1]->className->name);
|
||||
nextlc(line, col, 20);
|
||||
}
|
||||
move(y, x);
|
||||
refresh();
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
readPathlist()
|
||||
{
|
||||
char *pathstr;
|
||||
FILE *fyle;
|
||||
int i;
|
||||
|
||||
sprintf(pathFileName, "%s/.fredpaths", getenv("HOME"));
|
||||
if ((fyle = fopen(pathFileName,"r")) != NULL) {
|
||||
for (i=1; i<10; i++)
|
||||
fscanf(fyle, "%s\n", paths[i]);
|
||||
fclose(fyle);
|
||||
} else {
|
||||
for (i=1; i<10; i++)
|
||||
strcpy(paths[i], "./");
|
||||
}
|
||||
if ((pathstr = getenv("FREDPATH")) != NULL)
|
||||
strcpy(paths[0], pathstr);
|
||||
else
|
||||
strcpy(paths[0], "./");
|
||||
}
|
||||
|
||||
void
|
||||
writePathlist()
|
||||
{
|
||||
FILE *fyle;
|
||||
int i;
|
||||
|
||||
if ((fyle = fopen(pathFileName, "w")) != NULL) {
|
||||
for (i=1; i<10; i++)
|
||||
fprintf(fyle, "%s\n", paths[i]);
|
||||
fclose(fyle);
|
||||
} else
|
||||
lineError("can't write to pathlist file %s", pathFileName);
|
||||
}
|
||||
|
||||
void
|
||||
showPathlist()
|
||||
{
|
||||
int i;
|
||||
int y, x;
|
||||
|
||||
getyx(curscr, y, x);
|
||||
clearDisplay();
|
||||
for (i=0; i<10; ++i) {
|
||||
mvaddstr(i + 1, 0, " ");
|
||||
if (i == selectedPath) {
|
||||
editX = 0;
|
||||
editY = i + 1;
|
||||
editPath = paths[i];
|
||||
standout();
|
||||
}
|
||||
addstr(paths[i]);
|
||||
if (i == selectedPath) standend();
|
||||
clrtoeol();
|
||||
}
|
||||
move(y, x);
|
||||
refresh();
|
||||
}
|
||||
|
||||
boolean
|
||||
displayPathlist()
|
||||
{
|
||||
showPathlist();
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
revaluePath(firstc)
|
||||
char firstc;
|
||||
{
|
||||
char temp[80];
|
||||
|
||||
ungetch(firstc);
|
||||
mvaddstr(selectedPath + 1, 0, " ");
|
||||
clrtoeol();
|
||||
refresh();
|
||||
if (mygetstr(temp) && temp[0] != '\0') {
|
||||
strcpy(editPath, temp);
|
||||
changedFlag = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
editPathlist()
|
||||
{
|
||||
int y, x;
|
||||
char c;
|
||||
|
||||
echoLine("editing pathlist");
|
||||
getyx(curscr, y, x);
|
||||
showPathlist();
|
||||
changedFlag = FALSE;
|
||||
for (;;) {
|
||||
c = mygetch();
|
||||
if (c == DEL)
|
||||
break;
|
||||
else if (c == '\b') {
|
||||
if (selectedPath > 0)
|
||||
--selectedPath;
|
||||
} else if (c == '\r' || c == '\n' || c == ' ') {
|
||||
if (selectedPath < 9)
|
||||
++selectedPath;
|
||||
} else
|
||||
revaluePath(c);
|
||||
showPathlist();
|
||||
}
|
||||
if (changedFlag)
|
||||
writePathlist();
|
||||
move(y, x);
|
||||
strcpy(pathname, paths[selectedPath]);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
snarfRegion()
|
||||
{
|
||||
int i;
|
||||
byte *p;
|
||||
byte buf[10000];
|
||||
int regionSize;
|
||||
FILE *fyle;
|
||||
|
||||
c64_override_command(CMD_SAVE_CV);
|
||||
up(buf, (word) 2, CV_SIZE_SLOT);
|
||||
regionSize = buf[0] + buf[1]*256;
|
||||
up(buf, (word)(regionSize), CV_DATA_SLOT);
|
||||
Cont();
|
||||
p = buf;
|
||||
for (i=0; i<regionSize; ++i)
|
||||
cv[i] = *p++;
|
||||
}
|
||||
|
||||
boolean
|
||||
quit()
|
||||
{
|
||||
echoLine("quit");
|
||||
clearDisplay();
|
||||
refresh();
|
||||
writeFredStats();
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
setupFastlinkPort()
|
||||
{
|
||||
char *portstr;
|
||||
|
||||
portstr = getenv("FASTPORT");
|
||||
if (portstr != NULL) {
|
||||
if (strlen(portstr) < 3) {
|
||||
error("FASTPORT env variable must be of form: c;p\n");
|
||||
exit(1);
|
||||
} else {
|
||||
card = portstr[0] - '0';
|
||||
port = portstr[2] - '0';
|
||||
}
|
||||
}
|
||||
if (card < 0 || NCARDS <= card) {
|
||||
error("card number out of range\n");
|
||||
exit(1);
|
||||
}
|
||||
if (port < 0 || 2 < port) {
|
||||
error("port number out of range\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!testMode && !Init(card, port)) {
|
||||
error("unable to access device\n");
|
||||
Finish();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
doFredStuff()
|
||||
{
|
||||
char *pathstr;
|
||||
FILE *fyle;
|
||||
|
||||
pathname[0] = '\0';
|
||||
if ((pathstr = getenv("FREDPATH")) != NULL)
|
||||
strcpy(pathname, pathstr);
|
||||
readFredStats();
|
||||
readPathlist();
|
||||
if (!testMode)
|
||||
setupFastlinkPort();
|
||||
setupTerminal();
|
||||
|
||||
displayNoid = 0;
|
||||
undeleteBuffer = NULL;
|
||||
previousClass = 2;
|
||||
|
||||
strcpy(regionName, "/u0/habitat/empty.raw");
|
||||
echoLine("Fred version 1.0 (%s) -- type 'h' for help", DATE);
|
||||
while (processCommand())
|
||||
;
|
||||
refresh();
|
||||
endwin();
|
||||
}
|
||||
|
||||
boolean
|
||||
initC64editor()
|
||||
{
|
||||
/* system("down -S < /u0/aric/mic/Gr/all.out");*/
|
||||
system("down -S < /u0/habitat/reno.out");
|
||||
/* system("down -S < /u0/chip/reno.out");*/
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
sh()
|
||||
{
|
||||
char commandBuf[80];
|
||||
int y, x;
|
||||
|
||||
if (!getString(":", commandBuf)) {
|
||||
echoLine("aborted");
|
||||
return(TRUE);
|
||||
}
|
||||
getyx(curscr, y, x);
|
||||
clearDisplay();
|
||||
move(1, 0);
|
||||
refresh();
|
||||
echo(); noraw(); nl();
|
||||
system(commandBuf);
|
||||
noecho(); raw(); nonl();
|
||||
move(1, 47);
|
||||
refresh();
|
||||
echoLine("unix command:%s", commandBuf);
|
||||
refresh();
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
loadRegion()
|
||||
{
|
||||
if (!getRegionName())
|
||||
echoLine("aborted");
|
||||
else if (readRegion() && generateContentsVector()) {
|
||||
displayRegion();
|
||||
echoLine("loaded %s", regionName);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
saveRaw()
|
||||
{
|
||||
if (!getRegionName())
|
||||
echoLine("aborted");
|
||||
else {
|
||||
if (!testMode) {
|
||||
snarfRegion();
|
||||
degenerateContentsVector();
|
||||
}
|
||||
if (writeRegionRaw())
|
||||
echoLine("saved raw file %s", regionName);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
saveGriddle()
|
||||
{
|
||||
if (!getRegionName())
|
||||
echoLine("aborted");
|
||||
else {
|
||||
if (!testMode) {
|
||||
snarfRegion();
|
||||
degenerateContentsVector();
|
||||
}
|
||||
if (writeRegionGriddle())
|
||||
echoLine("saved griddle file %s", regionName);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
processCommand()
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
static char previousC = '\0';
|
||||
|
||||
if (previousC != '\r' && previousC != '\32')
|
||||
addstr(" -- Next?");
|
||||
refresh();
|
||||
c = mygetch();
|
||||
for (i=0; commandTable[i].commandKey != '\0'; ++i)
|
||||
if (commandTable[i].commandKey == c) {
|
||||
if (c != '\r' && c != '\32')
|
||||
echoLine(commandTable[i].echoName);
|
||||
fredStats[c]++;
|
||||
previousC = c;
|
||||
return (*(commandTable[i].commandFunction))();
|
||||
}
|
||||
lineError("'%s' is not a Fred command", keyName(c));
|
||||
previousC = c;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
pauseFred()
|
||||
{
|
||||
echo(); noraw(); nl();
|
||||
kill(0, SIGTSTP);
|
||||
noecho(); raw(); nonl();
|
||||
move(1, 47);
|
||||
refresh();
|
||||
reallyClearScreen();
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
refreshScreen()
|
||||
{
|
||||
reallyClearScreen();
|
||||
c64_key_command('r');
|
||||
return(TRUE);
|
||||
}
|
602
mamelink/griddle/fred2.c
Normal file
602
mamelink/griddle/fred2.c
Normal file
|
@ -0,0 +1,602 @@
|
|||
#include <curses.h>
|
||||
#include "griddleDefs.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
void
|
||||
mydown(buf, len, addr)
|
||||
byte *buf;
|
||||
word len;
|
||||
word addr;
|
||||
{
|
||||
if (!testMode)
|
||||
down(buf, len, addr);
|
||||
}
|
||||
|
||||
void
|
||||
displayRegion()
|
||||
{
|
||||
mydown(cv, (word)(cvLength), CV_DATA_SLOT);
|
||||
c64_override_command(CMD_LOAD_CV);
|
||||
}
|
||||
|
||||
boolean
|
||||
incColorPattern(dp, cmd)
|
||||
int dp;
|
||||
byte cmd;
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
if (displayNoid == 0)
|
||||
lineError("region has no color/pattern!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
if (isAvatar(displayNoid))
|
||||
fillWord(buf, ORIENT_OFFSET_AVA,
|
||||
(getWord(buf, ORIENT_OFFSET_AVA) + dp) & 0xFF);
|
||||
else
|
||||
fillWord(buf, ORIENT_OFFSET_OBJ,
|
||||
(getWord(buf, ORIENT_OFFSET_OBJ) + dp) & 0xFF);
|
||||
c64_key_command(cmd);
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
incPattern()
|
||||
{
|
||||
return(incColorPattern(8, 'p'));
|
||||
}
|
||||
|
||||
boolean
|
||||
decPattern()
|
||||
{
|
||||
return(incColorPattern(-8, 'P'));
|
||||
}
|
||||
|
||||
boolean
|
||||
incX(dx, cmd)
|
||||
int dx;
|
||||
byte cmd;
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
if (displayNoid == 0)
|
||||
lineError("region has no X-coordinate!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
if (isAvatar(displayNoid))
|
||||
fillWord(buf, X_OFFSET_AVA,
|
||||
(getWord(buf, X_OFFSET_AVA) + dx) & 0xFF);
|
||||
else
|
||||
fillWord(buf, X_OFFSET_OBJ,
|
||||
(getWord(buf, X_OFFSET_OBJ) + dx) & 0xFF);
|
||||
c64_key_command(cmd);
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
incY(dy, cmd)
|
||||
int dy;
|
||||
byte cmd;
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
if (displayNoid == 0)
|
||||
lineError("region has no Y-coordinate!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
if (isAvatar(displayNoid))
|
||||
fillWord(buf, Y_OFFSET_AVA,
|
||||
(getWord(buf, Y_OFFSET_AVA) + dy) & 0xFF);
|
||||
else
|
||||
fillWord(buf, Y_OFFSET_OBJ,
|
||||
(getWord(buf, Y_OFFSET_OBJ) + dy) & 0xFF);
|
||||
c64_key_command(cmd);
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
incX_4()
|
||||
{
|
||||
return(incX(4, '.'));
|
||||
}
|
||||
|
||||
boolean
|
||||
decX_4()
|
||||
{
|
||||
return(incX(-4, ','));
|
||||
}
|
||||
|
||||
boolean
|
||||
incY_1()
|
||||
{
|
||||
return(incY(1, '?'));
|
||||
}
|
||||
|
||||
boolean
|
||||
incY_10()
|
||||
{
|
||||
return(incY(10, '>'));
|
||||
}
|
||||
|
||||
boolean
|
||||
decY_1()
|
||||
{
|
||||
return(incY(-1, '/'));
|
||||
}
|
||||
|
||||
boolean
|
||||
decY_10()
|
||||
{
|
||||
return(incY(-10, '<'));
|
||||
}
|
||||
|
||||
boolean
|
||||
zeroGrState()
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
if (displayNoid == 0)
|
||||
lineError("region does not have grState!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
if (isAvatar(displayNoid))
|
||||
fillWord(buf, GRSTATE_OFFSET_AVA, 0);
|
||||
else
|
||||
fillWord(buf, GRSTATE_OFFSET_OBJ, 0);
|
||||
c64_key_command('s');
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
incGrState()
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
if (displayNoid == 0)
|
||||
lineError("region does not have grState!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
if (isAvatar(displayNoid))
|
||||
fillWord(buf, GRSTATE_OFFSET_AVA,
|
||||
getWord(buf, GRSTATE_OFFSET_AVA) + 1);
|
||||
else
|
||||
fillWord(buf, GRSTATE_OFFSET_OBJ,
|
||||
getWord(buf, GRSTATE_OFFSET_OBJ) + 1);
|
||||
c64_key_command('S');
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
toggleOrient()
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
if (displayNoid == 0)
|
||||
lineError("region does not have displayed orientation!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
if (isAvatar(displayNoid))
|
||||
fillWord(buf, ORIENT_OFFSET_AVA,
|
||||
getWord(buf, ORIENT_OFFSET_AVA) ^ 0x01);
|
||||
else
|
||||
fillWord(buf, ORIENT_OFFSET_OBJ,
|
||||
getWord(buf, ORIENT_OFFSET_OBJ) ^ 0x01);
|
||||
c64_key_command('o');
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
borderToggle()
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
if (noidArray[displayNoid]->class != CLASS_TRAP &&
|
||||
noidArray[displayNoid]->class != CLASS_SUPER_TRAP)
|
||||
lineError("current object is not a trapezoid!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
fillWord(buf, HEIGHT_OFFSET_TRAP,
|
||||
getWord(buf, HEIGHT_OFFSET_TRAP) ^ 0x80);
|
||||
c64_key_command('B');
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
flatChange()
|
||||
{
|
||||
byte *buf;
|
||||
int class;
|
||||
|
||||
class = noidArray[displayNoid]->class;
|
||||
if (class != CLASS_FLAT && class != CLASS_TRAP && class !=
|
||||
CLASS_SUPER_TRAP)
|
||||
lineError("inappropriate object for flat type change!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
fillWord(buf, TYPE_OFFSET_FLAT,
|
||||
(getWord(buf, TYPE_OFFSET_FLAT) + 1) & 3);
|
||||
c64_key_command('m');
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
foreground()
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
if (displayNoid == 0)
|
||||
lineError("region does not have foreground/background!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
if (isAvatar(displayNoid))
|
||||
fillWord(buf, Y_OFFSET_AVA,
|
||||
getWord(buf, Y_OFFSET_AVA) | 0x80);
|
||||
else
|
||||
fillWord(buf, Y_OFFSET_OBJ,
|
||||
getWord(buf, Y_OFFSET_OBJ) | 0x80);
|
||||
c64_key_command('f');
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
background()
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
if (displayNoid == 0)
|
||||
lineError("region does not have foreground/background!");
|
||||
else {
|
||||
buf = noidArray[displayNoid]->stateVector;
|
||||
if (isAvatar(displayNoid))
|
||||
fillWord(buf, Y_OFFSET_AVA,
|
||||
getWord(buf, Y_OFFSET_AVA) & 0x7F);
|
||||
else
|
||||
fillWord(buf, Y_OFFSET_OBJ,
|
||||
getWord(buf, Y_OFFSET_OBJ) & 0x7F);
|
||||
c64_key_command('b');
|
||||
displayOneObject(displayNoid);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
uploadRegion()
|
||||
{
|
||||
generateContentsVector();
|
||||
displayRegion();
|
||||
}
|
||||
|
||||
void
|
||||
homogenize(filename)
|
||||
char *filename;
|
||||
{
|
||||
char tempstr[80];
|
||||
char *tildeptr;
|
||||
char *index();
|
||||
|
||||
if ((tildeptr = index(filename, '~')) != NULL) {
|
||||
strncpy(tempstr, filename, tildeptr - filename);
|
||||
sprintf(tempstr + (tildeptr - filename), "%s%s",
|
||||
getenv("HOME"), tildeptr + 1);
|
||||
strcpy(filename, tempstr);
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
readRegion()
|
||||
{
|
||||
char regionFileName[80];
|
||||
|
||||
sprintf(regionFileName, "%s%s", pathname, regionName);
|
||||
homogenize(regionFileName);
|
||||
queueInputFile(saveString(regionFileName));
|
||||
if (openFirstFile(TRUE)) {
|
||||
resetRegionCounters();
|
||||
yyparse();
|
||||
echoLine("reading %d objects", objectCount);
|
||||
globalIdCounter += objectCount;
|
||||
displayNoid = 0;
|
||||
if (objectCount > 127)
|
||||
lineError("too many objects in region");
|
||||
return(TRUE);
|
||||
} else {
|
||||
lineError("can't open '%s'", regionFileName);
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
writeRegionRaw()
|
||||
{
|
||||
char regionFileName[80];
|
||||
int i;
|
||||
struct stat statBuf;
|
||||
|
||||
sprintf(regionFileName, "%s%s", pathname, regionName);
|
||||
homogenize(regionFileName);
|
||||
if (!promptDefault)
|
||||
if (stat(regionFileName, &statBuf) == 0)
|
||||
if (!promptYN("file already exists; replace? ")) {
|
||||
echoLine("write aborted");
|
||||
return(FALSE);
|
||||
}
|
||||
if ((rawFile = fopen(regionFileName, "w")) != NULL) {
|
||||
for (i=0; i<objectCount; ++i)
|
||||
outputRawObject(noidArray[i]);
|
||||
fclose(rawFile);
|
||||
rawFile = NULL;
|
||||
return(TRUE);
|
||||
} else {
|
||||
lineError("can't open '%s'", regionFileName);
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
writeRegionGriddle()
|
||||
{
|
||||
char regionFileName[80];
|
||||
int i;
|
||||
struct stat statBuf;
|
||||
|
||||
sprintf(regionFileName, "%s%s", pathname, regionName);
|
||||
homogenize(regionFileName);
|
||||
if (!promptDefault)
|
||||
if (stat(regionFileName, &statBuf) == 0)
|
||||
if (!promptYN("file already exists; replace? ")) {
|
||||
echoLine("write aborted");
|
||||
return(FALSE);
|
||||
}
|
||||
if ((griFile = fopen(regionFileName, "w")) != NULL) {
|
||||
for (i=0; i<objectCount; ++i)
|
||||
dumpObject(noidArray[i]);
|
||||
fclose(griFile);
|
||||
griFile = NULL;
|
||||
return(TRUE);
|
||||
} else {
|
||||
lineError("can't open '%s'", regionFileName);
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
keyName(key)
|
||||
char key;
|
||||
{
|
||||
static char result[10];
|
||||
int i;
|
||||
static struct {
|
||||
char key;
|
||||
char *name;
|
||||
} keyList[] = {
|
||||
' ', "SPACE", '\b', "BACKSPACE",
|
||||
'\t', "TAB", '\n', "LINE FEED",
|
||||
'\r', "RETURN", '\33', "ESC",
|
||||
'\177', "DEL"
|
||||
};
|
||||
|
||||
if ('!' <= key && key <= '~') {
|
||||
sprintf(result, "%c", key);
|
||||
return(result);
|
||||
}
|
||||
for (i=0; keyList[i].key != '\0'; ++i)
|
||||
if (keyList[i].key == key)
|
||||
return(keyList[i].name);
|
||||
if (key < ' ') {
|
||||
sprintf(result, "^%c", key + 0x40);
|
||||
return(result);
|
||||
}
|
||||
sprintf(result, "\\%o", key);
|
||||
return(result);
|
||||
}
|
||||
|
||||
int
|
||||
nextFreeNoid()
|
||||
{
|
||||
int noid;
|
||||
|
||||
for (noid=0; noid<objectCount; ++noid)
|
||||
if (noidArray[noid] == NULL)
|
||||
break;
|
||||
if (noid == objectCount)
|
||||
++objectCount;
|
||||
return(noid);
|
||||
}
|
||||
|
||||
void
|
||||
announceObject(noid, class)
|
||||
int noid;
|
||||
int class;
|
||||
{
|
||||
byte createPacket[7];
|
||||
byte *buf;
|
||||
void mydown();
|
||||
|
||||
if (class == 0)
|
||||
return;
|
||||
buf = noidArray[noid]->stateVector;
|
||||
createPacket[0] = class;
|
||||
createPacket[1] = 0;
|
||||
if (class == 1) {
|
||||
createPacket[2] = getByte(buf, STYLE_OFFSET_AVA);
|
||||
createPacket[3] = getWord(buf, X_OFFSET_AVA);
|
||||
createPacket[4] = getWord(buf, Y_OFFSET_AVA);
|
||||
createPacket[5] = getWord(buf, ORIENT_OFFSET_AVA);
|
||||
createPacket[6] = getWord(buf, GRSTATE_OFFSET_AVA);
|
||||
} else {
|
||||
createPacket[2] = getWord(buf, STYLE_OFFSET_OBJ);
|
||||
createPacket[3] = getWord(buf, X_OFFSET_OBJ);
|
||||
createPacket[4] = getWord(buf, Y_OFFSET_OBJ);
|
||||
createPacket[5] = getWord(buf, ORIENT_OFFSET_OBJ);
|
||||
createPacket[6] = getWord(buf, GRSTATE_OFFSET_OBJ);
|
||||
}
|
||||
mydown(createPacket, (word) 7, CREATE_DATA_SLOT);
|
||||
c64_override_command(CMD_CREATE);
|
||||
}
|
||||
|
||||
boolean
|
||||
nightMode()
|
||||
{
|
||||
c64_key_command('n');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
eraseBackground()
|
||||
{
|
||||
c64_key_command('e');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
walkto()
|
||||
{
|
||||
c64_key_command('w');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
showFlatTypes()
|
||||
{
|
||||
c64_key_command('g');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
peekContainer()
|
||||
{
|
||||
c64_key_command('l');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
containerOffsetRight()
|
||||
{
|
||||
c64_key_command('+');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
containerOffsetLeft()
|
||||
{
|
||||
c64_key_command('-');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
containerOffsetUp()
|
||||
{
|
||||
c64_key_command('@');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
containerOffsetDown()
|
||||
{
|
||||
c64_key_command('*');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
changeHold()
|
||||
{
|
||||
c64_key_command('=');
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
changeContainer()
|
||||
{
|
||||
int newContainer;
|
||||
int contCode;
|
||||
byte *cbuf;
|
||||
byte *obuf;
|
||||
|
||||
newContainer = touchObject();
|
||||
c64_touch_command(displayNoid);
|
||||
c64_key_command('C');
|
||||
c64_key_command('r');
|
||||
obuf = noidArray[displayNoid]->stateVector;
|
||||
cbuf = noidArray[newContainer]->stateVector;
|
||||
if (noidArray[newContainer]->class == 0)
|
||||
contCode = 0;
|
||||
else if (noidArray[newContainer]->class == 1)
|
||||
contCode = 1;
|
||||
else
|
||||
contCode = 2;
|
||||
if (isAvatar(displayNoid)) {
|
||||
if (contCode == 1)
|
||||
lineError("can't put avatar in another avatar!");
|
||||
else if (contCode == 0)
|
||||
fillLong(obuf, CONTAINER_OFFSET_AVA, 0);
|
||||
else
|
||||
fillLong(obuf, CONTAINER_OFFSET_AVA,
|
||||
getLong(cbuf, IDENT_OFFSET_OBJ));
|
||||
} else {
|
||||
fillLong(obuf, CONTAINER_OFFSET_OBJ,
|
||||
getLong(cbuf, IDENT_OFFSET_OBJ));
|
||||
fillWord(obuf, CONTAINER_TYPE_OFFSET_OBJ, contCode);
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
trapEdit()
|
||||
{
|
||||
char c;
|
||||
|
||||
if (noidArray[displayNoid]->class != CLASS_TRAP &&
|
||||
noidArray[displayNoid]->class != CLASS_SUPER_TRAP) {
|
||||
lineError("current object is not a trapezoid!");
|
||||
return(TRUE);
|
||||
}
|
||||
clearDisplay();
|
||||
mvprintw(1, 0, "L -- upper left corner");
|
||||
mvprintw(2, 0, "l -- lower left corner");
|
||||
mvprintw(3, 0, "R -- upper right corner");
|
||||
mvprintw(4, 0, "r -- lower right corner");
|
||||
mvprintw(5, 0, "x -- exit trapezoid edit mode");
|
||||
refresh();
|
||||
c64_key_command(TRAP_EDIT_KEY);
|
||||
while ((c = mygetch()) != 'x') {
|
||||
if (c == 'L') {
|
||||
echoLine("upper left");
|
||||
c64_key_command(UPPER_LEFT_KEY);
|
||||
} else if (c == 'l') {
|
||||
echoLine("lower left");
|
||||
c64_key_command(LOWER_LEFT_KEY);
|
||||
} else if (c == 'R') {
|
||||
echoLine("upper right");
|
||||
c64_key_command(UPPER_RIGHT_KEY);
|
||||
} else if (c == 'r') {
|
||||
echoLine("lower right");
|
||||
c64_key_command(LOWER_RIGHT_KEY);
|
||||
} else {
|
||||
lineError("not a trapezoid edit command!");
|
||||
}
|
||||
}
|
||||
echoLine("done editing trapezoid");
|
||||
c64_key_command(TRAP_EDIT_KEY);
|
||||
snarfRegion();
|
||||
degenerateContentsVector();
|
||||
displayOneObject(displayNoid);
|
||||
return(TRUE);
|
||||
}
|
350
mamelink/griddle/fscreen.c
Normal file
350
mamelink/griddle/fscreen.c
Normal file
|
@ -0,0 +1,350 @@
|
|||
#include <curses.h>
|
||||
#include "griddleDefs.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
static boolean unsavedFlag = FALSE;
|
||||
static char unsavedChar;
|
||||
|
||||
extern int yylval;
|
||||
|
||||
void
|
||||
echoLine(fmt, arg1, arg2, arg3)
|
||||
char *fmt;
|
||||
int arg1;
|
||||
int arg2;
|
||||
int arg3;
|
||||
{
|
||||
move(0, 0);
|
||||
refresh();
|
||||
clrtoeol();
|
||||
printw(fmt, arg1, arg2, arg3);
|
||||
refresh();
|
||||
}
|
||||
|
||||
void
|
||||
lineError(fmt, arg1, arg2, arg3)
|
||||
char *fmt;
|
||||
int arg1;
|
||||
int arg2;
|
||||
int arg3;
|
||||
{
|
||||
echoLine(fmt, arg1, arg2, arg3);
|
||||
putchar('\7');
|
||||
}
|
||||
|
||||
char
|
||||
mygetch()
|
||||
{
|
||||
if (unsavedFlag) {
|
||||
unsavedFlag = FALSE;
|
||||
return(unsavedChar);
|
||||
} else
|
||||
return(getch());
|
||||
}
|
||||
|
||||
void
|
||||
ungetch(c)
|
||||
char c;
|
||||
{
|
||||
unsavedChar = c;
|
||||
unsavedFlag = TRUE;
|
||||
}
|
||||
|
||||
boolean
|
||||
mygetstr(buf)
|
||||
char *buf;
|
||||
{
|
||||
char c;
|
||||
char *originalBuf;
|
||||
int x, y;
|
||||
int originalX;
|
||||
|
||||
originalBuf = buf;
|
||||
getyx(curscr, y, originalX);
|
||||
x = originalX;
|
||||
for (;;) {
|
||||
c = mygetch();
|
||||
if (c == CTRL_C || c == ESCAPE)
|
||||
return(FALSE);
|
||||
else if (c == '\n' || c == '\r' || c == EOF) {
|
||||
addch('\r');
|
||||
refresh();
|
||||
*buf = '\0';
|
||||
return(TRUE);
|
||||
} else if (c == '\b' || c == DEL) {
|
||||
if (buf > originalBuf) {
|
||||
mvclrtoeol(y, --x);
|
||||
--buf;
|
||||
}
|
||||
} else if (c == CTRL_U) {
|
||||
mvclrtoeol(y, x = originalX);
|
||||
buf = originalBuf;
|
||||
} else {
|
||||
addch(c);
|
||||
*buf++ = c;
|
||||
++x;
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
getString(prompt, buf)
|
||||
char *prompt;
|
||||
char *buf;
|
||||
{
|
||||
addstr(prompt);
|
||||
refresh();
|
||||
return(mygetstr(buf));
|
||||
}
|
||||
|
||||
int
|
||||
promptInt(prompt, defval)
|
||||
char *prompt;
|
||||
int defval;
|
||||
{
|
||||
char answer[80];
|
||||
char newPrompt[80];
|
||||
symbol *symb;
|
||||
symbol *lookupSymbol();
|
||||
|
||||
sprintf(newPrompt, " %s [%d] ? ", prompt, defval);
|
||||
if (!getString(newPrompt, answer))
|
||||
return(0);
|
||||
if (answer[0] == '\0')
|
||||
return(defval);
|
||||
else if (answer[0] == ESCAPE || answer[0] == CTRL_C)
|
||||
return(-1);
|
||||
else if ('0' <= answer[0] && answer[0] <= '9')
|
||||
return(atoi(answer));
|
||||
else {
|
||||
symb = lookupSymbol(answer);
|
||||
if (symb->type != CLASS_SYM) {
|
||||
lineError("not a class name!");
|
||||
return(-1);
|
||||
}
|
||||
return(symb->def.class);
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
promptStr(prompt, defval, resultBuf)
|
||||
char *prompt;
|
||||
char *defval;
|
||||
char *resultBuf;
|
||||
{
|
||||
char answer[80];
|
||||
char newPrompt[80];
|
||||
|
||||
sprintf(newPrompt, " %s [\"%s\"] ? ", prompt, defval);
|
||||
if (!getString(newPrompt, answer))
|
||||
return(FALSE);
|
||||
if (answer[0] == '\0') {
|
||||
promptDefault = TRUE;
|
||||
if (defval != resultBuf)
|
||||
strcpy(resultBuf, defval);
|
||||
} else {
|
||||
promptDefault = FALSE;
|
||||
strcpy(resultBuf, answer);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
boolean
|
||||
promptYN(prompt)
|
||||
char *prompt;
|
||||
{
|
||||
char answer[80];
|
||||
|
||||
mvclrtoeol(0, 0);
|
||||
for (;;) {
|
||||
if (getString(prompt, answer)) {
|
||||
if (answer[0] == 'Y' || answer[0] == 'y')
|
||||
return(TRUE);
|
||||
else if (answer[0] == 'N' || answer[0] == 'n')
|
||||
return(FALSE);
|
||||
}
|
||||
lineError("please answer yes or no!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fieldPrompt(line, col, aField, buf, highlight)
|
||||
int line;
|
||||
int col;
|
||||
field *aField;
|
||||
byte *buf;
|
||||
boolean highlight;
|
||||
{
|
||||
mvaddstr(line, col, " ");
|
||||
if (highlight)
|
||||
standout();
|
||||
printw("%s:", aField->name->name);
|
||||
if (highlight)
|
||||
standend();
|
||||
addstr(" ");
|
||||
clrtoeol();
|
||||
refresh();
|
||||
}
|
||||
|
||||
value *
|
||||
parseValue(dataptr)
|
||||
char **dataptr;
|
||||
{
|
||||
char *data;
|
||||
value *val;
|
||||
value *buildValue();
|
||||
valueType resultType, newType;
|
||||
boolean typeTest;
|
||||
int sign;
|
||||
|
||||
if (dataptr == NULL || *dataptr == NULL)
|
||||
return(buildValue(VAL_INTEGER, 0));
|
||||
fredLexString = *dataptr;
|
||||
resultType = newType = VAL_INTEGER;
|
||||
val = NULL;
|
||||
sign = 1;
|
||||
for (;;) {
|
||||
typeTest = FALSE;
|
||||
switch (yylex()) {
|
||||
Case Number:
|
||||
val = buildValue(resultType, yylval*sign);
|
||||
Case String:
|
||||
val = buildValue(VAL_STRING, yylval);
|
||||
typeTest = TRUE;
|
||||
Case BitString:
|
||||
val = buildValue(VAL_BITSTRING, yylval);
|
||||
typeTest = TRUE;
|
||||
Case '-':
|
||||
sign = -sign;
|
||||
Case A:
|
||||
newType = VAL_AVATAR;
|
||||
typeTest = TRUE;
|
||||
Case O:
|
||||
newType = VAL_OBJECT;
|
||||
typeTest = TRUE;
|
||||
Case R:
|
||||
newType = VAL_REGION;
|
||||
typeTest = TRUE;
|
||||
Case ',':
|
||||
if (resultType != VAL_INTEGER)
|
||||
lineError("dangling type!");
|
||||
*dataptr = fredLexString;
|
||||
return(val);
|
||||
Case 0:
|
||||
if (resultType != VAL_INTEGER)
|
||||
lineError("dangling type!");
|
||||
*dataptr = NULL;
|
||||
return(val);
|
||||
Default:
|
||||
lineError("syntax error!");
|
||||
if (val == NULL)
|
||||
val = buildValue(VAL_INTEGER, 0);
|
||||
}
|
||||
if (typeTest && resultType != VAL_INTEGER)
|
||||
lineError("type mismatch!");
|
||||
else
|
||||
resultType = newType;
|
||||
}
|
||||
}
|
||||
|
||||
value *
|
||||
parseInt(dataptr)
|
||||
char **dataptr;
|
||||
{
|
||||
value *val;
|
||||
value *buildNumber();
|
||||
|
||||
val = parseValue(dataptr);
|
||||
if (val != NULL && !isInteger(val)) {
|
||||
lineError("invalid data type for integer value!");
|
||||
val = buildNumber(0);
|
||||
}
|
||||
return(val);
|
||||
}
|
||||
|
||||
value *
|
||||
parseBit(dataptr)
|
||||
char **dataptr;
|
||||
{
|
||||
value *val;
|
||||
value *buildNumber();
|
||||
|
||||
val = parseValue(dataptr);
|
||||
if (val != NULL && !isInteger(val) && val->dataType != VAL_BITSTRING){
|
||||
lineError("invalid data type for bitstring value!");
|
||||
val = buildNumber(0);
|
||||
}
|
||||
return(val);
|
||||
}
|
||||
|
||||
char *
|
||||
parseString(dataptr)
|
||||
char **dataptr;
|
||||
{
|
||||
value *val;
|
||||
|
||||
if (dataptr == NULL || *dataptr == NULL)
|
||||
return(NULL);
|
||||
val = parseValue(dataptr);
|
||||
if (isString(val))
|
||||
return((char *)(val->value));
|
||||
else {
|
||||
lineError("invalid data type for string value!");
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
getRegionName()
|
||||
{
|
||||
return(promptStr("name", regionName, regionName));
|
||||
}
|
||||
|
||||
void
|
||||
hexDump(buf, len)
|
||||
byte *buf;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
int line;
|
||||
|
||||
clearDisplay();
|
||||
for (i=0, line=1; i<len; ++i) {
|
||||
if ((i & 7) == 0) mvprintw(line, 0, "0x%04x: ", i);
|
||||
printw("0x%02x ", buf[i]);
|
||||
if ((i & 7) == 7) ++line;
|
||||
if (line == LINES-1) {
|
||||
mvprintw(line, 0, "--more--");
|
||||
refresh();
|
||||
mygetch();
|
||||
clearDisplay();
|
||||
line = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WINDOW *clearWindow;
|
||||
|
||||
void
|
||||
setupTerminal()
|
||||
{
|
||||
WINDOW *newwin();
|
||||
|
||||
initscr();
|
||||
noecho();
|
||||
raw();
|
||||
nonl();
|
||||
erase();
|
||||
refresh();
|
||||
clearWindow = newwin(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
reallyClearScreen()
|
||||
{
|
||||
touchwin(clearWindow);
|
||||
wrefresh(clearWindow);
|
||||
touchwin(stdscr);
|
||||
refresh();
|
||||
}
|
535
mamelink/griddle/griddle.c
Normal file
535
mamelink/griddle/griddle.c
Normal file
|
@ -0,0 +1,535 @@
|
|||
|
||||
# line 2 "griddle.y"
|
||||
#include "griddleDefs.h"
|
||||
# define Name 257
|
||||
# define Number 258
|
||||
# define String 259
|
||||
# define BitString 260
|
||||
# define Rawline 261
|
||||
# define INCLUDE 262
|
||||
# define DEFINE 263
|
||||
# define ENDDEFINE 264
|
||||
# define USE 265
|
||||
# define AVAID 266
|
||||
# define BIN15 267
|
||||
# define BIN31 268
|
||||
# define BIT 269
|
||||
# define BYTE 270
|
||||
# define CHARACTER 271
|
||||
# define ENTITY 272
|
||||
# define FATWORD 273
|
||||
# define OBJID 274
|
||||
# define REGID 275
|
||||
# define VARSTRING 276
|
||||
# define WORDS 277
|
||||
# define A 278
|
||||
# define O 279
|
||||
# define R 280
|
||||
# define OR 281
|
||||
# define XOR 282
|
||||
# define AND 283
|
||||
# define ADD 284
|
||||
# define SUB 285
|
||||
# define MUL 286
|
||||
# define DIV 287
|
||||
# define MOD 288
|
||||
# define UMINUS 289
|
||||
# define NOT 290
|
||||
#define yyclearin yychar = -1
|
||||
#define yyerrok yyerrflag = 0
|
||||
extern int yychar;
|
||||
extern short yyerrflag;
|
||||
#ifndef YYMAXDEPTH
|
||||
#define YYMAXDEPTH 150
|
||||
#endif
|
||||
#ifndef YYSTYPE
|
||||
#define YYSTYPE int
|
||||
#endif
|
||||
YYSTYPE yylval, yyval;
|
||||
# define YYERRCODE 256
|
||||
short yyexca[] ={
|
||||
-1, 1,
|
||||
0, -1,
|
||||
-2, 0,
|
||||
};
|
||||
# define YYNPROD 60
|
||||
# define YYLAST 287
|
||||
short yyact[]={
|
||||
|
||||
21, 73, 29, 36, 37, 35, 30, 31, 32, 33,
|
||||
34, 95, 37, 35, 30, 31, 32, 33, 34, 62,
|
||||
32, 33, 34, 15, 36, 37, 35, 30, 31, 32,
|
||||
33, 34, 35, 30, 31, 32, 33, 34, 30, 31,
|
||||
32, 33, 34, 85, 79, 80, 81, 88, 78, 87,
|
||||
86, 84, 83, 89, 82, 8, 52, 52, 96, 12,
|
||||
9, 10, 74, 11, 67, 53, 27, 46, 102, 93,
|
||||
77, 46, 65, 92, 94, 14, 99, 66, 76, 72,
|
||||
16, 51, 50, 45, 28, 97, 2, 48, 13, 7,
|
||||
6, 38, 39, 40, 41, 42, 43, 71, 5, 4,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 3, 1,
|
||||
0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 63, 47,
|
||||
0, 69, 0, 47, 70, 0, 0, 0, 0, 0,
|
||||
0, 0, 90, 75, 0, 0, 91, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 36,
|
||||
37, 35, 30, 31, 32, 33, 34, 100, 98, 75,
|
||||
101, 0, 0, 0, 0, 0, 103, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
67, 0, 0, 0, 67, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 17, 18, 19,
|
||||
20, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 24, 25,
|
||||
26, 0, 0, 0, 0, 22, 0, 0, 0, 0,
|
||||
23, 36, 37, 35, 30, 31, 32, 33, 34, 36,
|
||||
37, 35, 30, 31, 32, 33, 34, 44, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 53, 53,
|
||||
0, 0, 0, 0, 0, 68, 49 };
|
||||
short yypact[]={
|
||||
|
||||
-202,-202,-1000,-1000,-1000,-1000,-1000,-1000, 14,-236,
|
||||
-40,-191,-1000,-1000, -40,-1000,-257,-1000,-1000,-1000,
|
||||
-1000, -40, -40, -40, -40, -40, -40, 10,-278, 22,
|
||||
-40, -40, -40, -40, -40, -40, -40, -40, -22,-1000,
|
||||
-1000,-278,-278,-278, 6,-1000, -40,-193, 21,-1000,
|
||||
-1000,-1000,-192, 39,-266,-266,-1000,-1000,-1000,-246,
|
||||
-270,-251,-1000,-1000,-122, -63,-1000, 20,-1000,-1000,
|
||||
-1000,-223, -40,-193,-1000,-1000, -40, 13,-1000,-1000,
|
||||
-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
|
||||
-30, -67, 41,-278, -40, 18,-1000, -40, 41,-223,
|
||||
-278, 7, -40, 41 };
|
||||
short yypgo[]={
|
||||
|
||||
0, 109, 86, 108, 99, 98, 90, 89, 69, 87,
|
||||
82, 81, 70, 73, 83, 72, 77 };
|
||||
short yyr1[]={
|
||||
|
||||
0, 1, 1, 2, 2, 2, 2, 2, 7, 3,
|
||||
4, 5, 5, 9, 9, 10, 10, 11, 11, 11,
|
||||
11, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
12, 12, 12, 6, 6, 14, 14, 15, 15, 16,
|
||||
13, 13, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8 };
|
||||
short yyr2[]={
|
||||
|
||||
0, 1, 2, 1, 1, 1, 1, 1, 1, 3,
|
||||
2, 5, 4, 1, 2, 1, 2, 3, 6, 5,
|
||||
8, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 4, 3, 5, 3, 1, 2, 3,
|
||||
1, 3, 1, 1, 1, 1, 3, 2, 2, 2,
|
||||
2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
short yychk[]={
|
||||
|
||||
-1000, -1, -2, -3, -4, -5, -6, -7, 257, 262,
|
||||
263, 265, 261, -2, 61, 259, -8, 257, 258, 259,
|
||||
260, 40, 285, 290, 278, 279, 280, 257, -8, 259,
|
||||
284, 285, 286, 287, 288, 283, 281, 282, -8, -8,
|
||||
-8, -8, -8, -8, 257, -14, 61, 123, -9, 264,
|
||||
-10, -11, 35, 257, -8, -8, -8, -8, -8, -8,
|
||||
-8, -8, 41, -14, -8, -15, -16, 257, 264, -10,
|
||||
-11, 58, 40, 123, 125, -16, 58, -12, 271, 267,
|
||||
268, 269, 277, 275, 274, 266, 273, 272, 270, 276,
|
||||
-8, -15, -13, -8, 61, 41, 125, 44, -13, 58,
|
||||
-8, -12, 61, -13 };
|
||||
short yydef[]={
|
||||
|
||||
0, -2, 1, 3, 4, 5, 6, 7, 0, 0,
|
||||
0, 0, 8, 2, 0, 10, 0, 42, 43, 44,
|
||||
45, 0, 0, 0, 0, 0, 0, 0, 9, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 47,
|
||||
48, 49, 50, 51, 0, 34, 0, 0, 0, 12,
|
||||
13, 15, 0, 0, 52, 53, 54, 55, 56, 57,
|
||||
58, 59, 46, 33, 0, 0, 37, 0, 11, 14,
|
||||
16, 0, 0, 0, 36, 38, 0, 17, 21, 22,
|
||||
23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
|
||||
0, 0, 39, 40, 0, 0, 35, 0, 19, 0,
|
||||
41, 18, 0, 20 };
|
||||
#ifndef lint
|
||||
static char yaccpar_sccsid[] = "@(#)yaccpar 1.1 83/07/20 SMI"; /* from UCB 4.1 83/02/11 */
|
||||
#endif
|
||||
|
||||
#
|
||||
# define YYFLAG -1000
|
||||
# define YYERROR goto yyerrlab
|
||||
# define YYACCEPT return(0)
|
||||
# define YYABORT return(1)
|
||||
|
||||
/* parser for yacc output */
|
||||
|
||||
#ifdef YYDEBUG
|
||||
int yydebug = 0; /* 1 for debugging */
|
||||
#endif
|
||||
YYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */
|
||||
int yychar = -1; /* current input token number */
|
||||
int yynerrs = 0; /* number of errors */
|
||||
short yyerrflag = 0; /* error recovery flag */
|
||||
|
||||
yyparse() {
|
||||
|
||||
short yys[YYMAXDEPTH];
|
||||
short yyj, yym;
|
||||
register YYSTYPE *yypvt;
|
||||
register short yystate, *yyps, yyn;
|
||||
register YYSTYPE *yypv;
|
||||
register short *yyxi;
|
||||
|
||||
yystate = 0;
|
||||
yychar = -1;
|
||||
yynerrs = 0;
|
||||
yyerrflag = 0;
|
||||
yyps= &yys[-1];
|
||||
yypv= &yyv[-1];
|
||||
|
||||
yystack: /* put a state and value onto the stack */
|
||||
|
||||
#ifdef YYDEBUG
|
||||
if( yydebug ) printf( "state %d, char 0%o\n", yystate, yychar );
|
||||
#endif
|
||||
if( ++yyps> &yys[YYMAXDEPTH] ) { yyerror( "yacc stack overflow" ); return(1); }
|
||||
*yyps = yystate;
|
||||
++yypv;
|
||||
*yypv = yyval;
|
||||
|
||||
yynewstate:
|
||||
|
||||
yyn = yypact[yystate];
|
||||
|
||||
if( yyn<= YYFLAG ) goto yydefault; /* simple state */
|
||||
|
||||
if( yychar<0 ) if( (yychar=yylex())<0 ) yychar=0;
|
||||
if( (yyn += yychar)<0 || yyn >= YYLAST ) goto yydefault;
|
||||
|
||||
if( yychk[ yyn=yyact[ yyn ] ] == yychar ){ /* valid shift */
|
||||
yychar = -1;
|
||||
yyval = yylval;
|
||||
yystate = yyn;
|
||||
if( yyerrflag > 0 ) --yyerrflag;
|
||||
goto yystack;
|
||||
}
|
||||
|
||||
yydefault:
|
||||
/* default state action */
|
||||
|
||||
if( (yyn=yydef[yystate]) == -2 ) {
|
||||
if( yychar<0 ) if( (yychar=yylex())<0 ) yychar = 0;
|
||||
/* look through exception table */
|
||||
|
||||
for( yyxi=yyexca; (*yyxi!= (-1)) || (yyxi[1]!=yystate) ; yyxi += 2 ) ; /* VOID */
|
||||
|
||||
while( *(yyxi+=2) >= 0 ){
|
||||
if( *yyxi == yychar ) break;
|
||||
}
|
||||
if( (yyn = yyxi[1]) < 0 ) return(0); /* accept */
|
||||
}
|
||||
|
||||
if( yyn == 0 ){ /* error */
|
||||
/* error ... attempt to resume parsing */
|
||||
|
||||
switch( yyerrflag ){
|
||||
|
||||
case 0: /* brand new error */
|
||||
|
||||
yyerror( "syntax error" );
|
||||
yyerrlab:
|
||||
++yynerrs;
|
||||
|
||||
case 1:
|
||||
case 2: /* incompletely recovered error ... try again */
|
||||
|
||||
yyerrflag = 3;
|
||||
|
||||
/* find a state where "error" is a legal shift action */
|
||||
|
||||
while ( yyps >= yys ) {
|
||||
yyn = yypact[*yyps] + YYERRCODE;
|
||||
if( yyn>= 0 && yyn < YYLAST && yychk[yyact[yyn]] == YYERRCODE ){
|
||||
yystate = yyact[yyn]; /* simulate a shift of "error" */
|
||||
goto yystack;
|
||||
}
|
||||
yyn = yypact[*yyps];
|
||||
|
||||
/* the current yyps has no shift onn "error", pop stack */
|
||||
|
||||
#ifdef YYDEBUG
|
||||
if( yydebug ) printf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1] );
|
||||
#endif
|
||||
--yyps;
|
||||
--yypv;
|
||||
}
|
||||
|
||||
/* there is no state on the stack with an error shift ... abort */
|
||||
|
||||
yyabort:
|
||||
return(1);
|
||||
|
||||
|
||||
case 3: /* no shift yet; clobber input char */
|
||||
|
||||
#ifdef YYDEBUG
|
||||
if( yydebug ) printf( "error recovery discards char %d\n", yychar );
|
||||
#endif
|
||||
|
||||
if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */
|
||||
yychar = -1;
|
||||
goto yynewstate; /* try again in the same state */
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* reduction by production yyn */
|
||||
|
||||
#ifdef YYDEBUG
|
||||
if( yydebug ) printf("reduce %d\n",yyn);
|
||||
#endif
|
||||
yyps -= yyr2[yyn];
|
||||
yypvt = yypv;
|
||||
yypv -= yyr2[yyn];
|
||||
yyval = yypv[1];
|
||||
yym=yyn;
|
||||
/* consult goto table to find next state */
|
||||
yyn = yyr1[yyn];
|
||||
yyj = yypgo[yyn] + *yyps + 1;
|
||||
if( yyj>=YYLAST || yychk[ yystate = yyact[yyj] ] != -yyn ) yystate = yyact[yypgo[yyn]];
|
||||
switch(yym){
|
||||
|
||||
case 8:
|
||||
# line 35 "griddle.y"
|
||||
{
|
||||
executeRawline(yypvt[-0]);
|
||||
} break;
|
||||
case 9:
|
||||
# line 42 "griddle.y"
|
||||
{
|
||||
executeAssignment(yypvt[-2], yypvt[-0]);
|
||||
} break;
|
||||
case 10:
|
||||
# line 49 "griddle.y"
|
||||
{
|
||||
executeInclude(yypvt[-0]);
|
||||
} break;
|
||||
case 11:
|
||||
# line 56 "griddle.y"
|
||||
{
|
||||
yyval = executeDefine(yypvt[-3], yypvt[-2], yypvt[-1]);
|
||||
} break;
|
||||
case 12:
|
||||
# line 60 "griddle.y"
|
||||
{
|
||||
yyval = executeDefine(yypvt[-2], yypvt[-1], NULL);
|
||||
} break;
|
||||
case 13:
|
||||
# line 67 "griddle.y"
|
||||
{
|
||||
yyval = buildFieldList(NULL, yypvt[-0]);
|
||||
} break;
|
||||
case 14:
|
||||
# line 71 "griddle.y"
|
||||
{
|
||||
yyval = buildFieldList(yypvt[-1], yypvt[-0]);
|
||||
} break;
|
||||
case 15:
|
||||
# line 78 "griddle.y"
|
||||
{
|
||||
yyval = yypvt[-0];
|
||||
} break;
|
||||
case 16:
|
||||
# line 82 "griddle.y"
|
||||
{
|
||||
yyval = invisifyField(yypvt[-0]);
|
||||
} break;
|
||||
case 17:
|
||||
# line 89 "griddle.y"
|
||||
{
|
||||
yyval = buildField(yypvt[-2], buildExpr(NUM_EXPR, 1), yypvt[-0], NULL);
|
||||
} break;
|
||||
case 18:
|
||||
# line 93 "griddle.y"
|
||||
{
|
||||
yyval = buildField(yypvt[-5], yypvt[-3], yypvt[-0], NULL);
|
||||
} break;
|
||||
case 19:
|
||||
# line 97 "griddle.y"
|
||||
{
|
||||
yyval = buildField(yypvt[-4], buildExpr(NUM_EXPR, 1), yypvt[-2], yypvt[-0]);
|
||||
} break;
|
||||
case 20:
|
||||
# line 101 "griddle.y"
|
||||
{
|
||||
yyval = buildField(yypvt[-7], yypvt[-5], yypvt[-2], yypvt[-0]);
|
||||
} break;
|
||||
case 21:
|
||||
# line 107 "griddle.y"
|
||||
{ yyval = (int) FIELD_CHARACTER; } break;
|
||||
case 22:
|
||||
# line 108 "griddle.y"
|
||||
{ yyval = (int) FIELD_BIN15; } break;
|
||||
case 23:
|
||||
# line 109 "griddle.y"
|
||||
{ yyval = (int) FIELD_BIN31; } break;
|
||||
case 24:
|
||||
# line 110 "griddle.y"
|
||||
{ yyval = (int) FIELD_BIT; } break;
|
||||
case 25:
|
||||
# line 111 "griddle.y"
|
||||
{ yyval = (int) FIELD_WORDS; } break;
|
||||
case 26:
|
||||
# line 112 "griddle.y"
|
||||
{ yyval = (int) FIELD_REGID; } break;
|
||||
case 27:
|
||||
# line 113 "griddle.y"
|
||||
{ yyval = (int) FIELD_OBJID; } break;
|
||||
case 28:
|
||||
# line 114 "griddle.y"
|
||||
{ yyval = (int) FIELD_AVAID; } break;
|
||||
case 29:
|
||||
# line 115 "griddle.y"
|
||||
{ yyval = (int) FIELD_FATWORD; } break;
|
||||
case 30:
|
||||
# line 116 "griddle.y"
|
||||
{ yyval = (int) FIELD_ENTITY; } break;
|
||||
case 31:
|
||||
# line 117 "griddle.y"
|
||||
{ yyval = (int) FIELD_BYTE; } break;
|
||||
case 32:
|
||||
# line 118 "griddle.y"
|
||||
{ yyval = (int) FIELD_VARSTRING; } break;
|
||||
case 33:
|
||||
# line 123 "griddle.y"
|
||||
{
|
||||
executeUse(yypvt[-2], yypvt[-1], yypvt[-0]);
|
||||
} break;
|
||||
case 34:
|
||||
# line 127 "griddle.y"
|
||||
{
|
||||
executeUse(yypvt[-1], NULL, yypvt[-0]);
|
||||
} break;
|
||||
case 35:
|
||||
# line 134 "griddle.y"
|
||||
{
|
||||
yyval = buildObjectTail(yypvt[-3], yypvt[-1]);
|
||||
} break;
|
||||
case 36:
|
||||
# line 138 "griddle.y"
|
||||
{
|
||||
yyval = buildObjectTail(NULL, yypvt[-1]);
|
||||
} break;
|
||||
case 37:
|
||||
# line 145 "griddle.y"
|
||||
{
|
||||
yyval = buildPropertyList(NULL, yypvt[-0]);
|
||||
} break;
|
||||
case 38:
|
||||
# line 149 "griddle.y"
|
||||
{
|
||||
yyval = buildPropertyList(yypvt[-1], yypvt[-0]);
|
||||
} break;
|
||||
case 39:
|
||||
# line 156 "griddle.y"
|
||||
{
|
||||
yyval = buildProperty(yypvt[-2], yypvt[-0]);
|
||||
} break;
|
||||
case 40:
|
||||
# line 163 "griddle.y"
|
||||
{
|
||||
yyval = buildExprList(NULL, yypvt[-0]);
|
||||
} break;
|
||||
case 41:
|
||||
# line 167 "griddle.y"
|
||||
{
|
||||
yyval = buildExprList(yypvt[-2], yypvt[-0]);
|
||||
} break;
|
||||
case 42:
|
||||
# line 174 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(ID_EXPR, yypvt[-0]);
|
||||
} break;
|
||||
case 43:
|
||||
# line 178 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(NUM_EXPR, yypvt[-0]);
|
||||
} break;
|
||||
case 44:
|
||||
# line 182 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(STRING_EXPR, yypvt[-0]);
|
||||
} break;
|
||||
case 45:
|
||||
# line 186 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(BITSTRING_EXPR, yypvt[-0]);
|
||||
} break;
|
||||
case 46:
|
||||
# line 190 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(EXPR_EXPR, yypvt[-1]);
|
||||
} break;
|
||||
case 47:
|
||||
# line 194 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(UNOP_EXPR, UMINUS, yypvt[-0]);
|
||||
} break;
|
||||
case 48:
|
||||
# line 198 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(UNOP_EXPR, NOT, yypvt[-0]);
|
||||
} break;
|
||||
case 49:
|
||||
# line 202 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(UNOP_EXPR, A, yypvt[-0]);
|
||||
} break;
|
||||
case 50:
|
||||
# line 206 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(UNOP_EXPR, O, yypvt[-0]);
|
||||
} break;
|
||||
case 51:
|
||||
# line 210 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(UNOP_EXPR, R, yypvt[-0]);
|
||||
} break;
|
||||
case 52:
|
||||
# line 214 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(BIN_EXPR, yypvt[-2], ADD, yypvt[-0]);
|
||||
} break;
|
||||
case 53:
|
||||
# line 218 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(BIN_EXPR, yypvt[-2], SUB, yypvt[-0]);
|
||||
} break;
|
||||
case 54:
|
||||
# line 222 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(BIN_EXPR, yypvt[-2], MUL, yypvt[-0]);
|
||||
} break;
|
||||
case 55:
|
||||
# line 226 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(BIN_EXPR, yypvt[-2], DIV, yypvt[-0]);
|
||||
} break;
|
||||
case 56:
|
||||
# line 230 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(BIN_EXPR, yypvt[-2], MOD, yypvt[-0]);
|
||||
} break;
|
||||
case 57:
|
||||
# line 234 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(BIN_EXPR, yypvt[-2], AND, yypvt[-0]);
|
||||
} break;
|
||||
case 58:
|
||||
# line 238 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(BIN_EXPR, yypvt[-2], OR, yypvt[-0]);
|
||||
} break;
|
||||
case 59:
|
||||
# line 242 "griddle.y"
|
||||
{
|
||||
yyval = buildExpr(BIN_EXPR, yypvt[-2], XOR, yypvt[-0]);
|
||||
} break;
|
||||
}
|
||||
goto yystack; /* stack new state and value */
|
||||
|
||||
}
|
245
mamelink/griddle/griddle.y
Normal file
245
mamelink/griddle/griddle.y
Normal file
|
@ -0,0 +1,245 @@
|
|||
%{
|
||||
#include "griddleDefs.h"
|
||||
%}
|
||||
|
||||
%token Name Number String BitString Rawline
|
||||
%token INCLUDE DEFINE ENDDEFINE USE
|
||||
%token AVAID BIN15 BIN31 BIT BYTE CHARACTER ENTITY FATWORD OBJID REGID
|
||||
%token VARSTRING WORDS
|
||||
|
||||
%left A O R
|
||||
%left OR
|
||||
%left XOR
|
||||
%left AND
|
||||
%left ADD SUB
|
||||
%left MUL DIV MOD
|
||||
%right UMINUS NOT
|
||||
|
||||
%%
|
||||
|
||||
statementList:
|
||||
statement /* na */
|
||||
| statementList statement /* na */
|
||||
;
|
||||
|
||||
statement:
|
||||
assignmentStatement /* na */
|
||||
| includeStatement /* na */
|
||||
| defineStatement /* na */
|
||||
| objectUseStatement /* na */
|
||||
| rawStatement /* na */
|
||||
;
|
||||
|
||||
rawStatement:
|
||||
Rawline
|
||||
{
|
||||
executeRawline($1);
|
||||
}
|
||||
;
|
||||
|
||||
assignmentStatement:
|
||||
Name '=' expr
|
||||
{
|
||||
executeAssignment($1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
includeStatement:
|
||||
INCLUDE String
|
||||
{
|
||||
executeInclude($2);
|
||||
}
|
||||
;
|
||||
|
||||
defineStatement:
|
||||
DEFINE expr String fieldList ENDDEFINE
|
||||
{
|
||||
$$ = executeDefine($2, $3, $4);
|
||||
}
|
||||
| DEFINE expr String ENDDEFINE
|
||||
{
|
||||
$$ = executeDefine($2, $3, NULL);
|
||||
}
|
||||
;
|
||||
|
||||
fieldList:
|
||||
field
|
||||
{
|
||||
$$ = buildFieldList(NULL, $1);
|
||||
}
|
||||
| fieldList field
|
||||
{
|
||||
$$ = buildFieldList($1, $2);
|
||||
}
|
||||
;
|
||||
|
||||
field:
|
||||
basicField
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| '#' basicField
|
||||
{
|
||||
$$ = invisifyField($2);
|
||||
}
|
||||
;
|
||||
|
||||
basicField:
|
||||
Name ':' fieldType
|
||||
{
|
||||
$$ = buildField($1, buildExpr(NUM_EXPR, 1), $3, NULL);
|
||||
}
|
||||
| Name '(' expr ')' ':' fieldType
|
||||
{
|
||||
$$ = buildField($1, $3, $6, NULL);
|
||||
}
|
||||
| Name ':' fieldType '=' exprList
|
||||
{
|
||||
$$ = buildField($1, buildExpr(NUM_EXPR, 1), $3, $5);
|
||||
}
|
||||
| Name '(' expr ')' ':' fieldType '=' exprList
|
||||
{
|
||||
$$ = buildField($1, $3, $6, $8);
|
||||
}
|
||||
;
|
||||
|
||||
fieldType:
|
||||
CHARACTER { $$ = (int) FIELD_CHARACTER; }
|
||||
| BIN15 { $$ = (int) FIELD_BIN15; }
|
||||
| BIN31 { $$ = (int) FIELD_BIN31; }
|
||||
| BIT { $$ = (int) FIELD_BIT; }
|
||||
| WORDS { $$ = (int) FIELD_WORDS; }
|
||||
| REGID { $$ = (int) FIELD_REGID; }
|
||||
| OBJID { $$ = (int) FIELD_OBJID; }
|
||||
| AVAID { $$ = (int) FIELD_AVAID; }
|
||||
| FATWORD { $$ = (int) FIELD_FATWORD; }
|
||||
| ENTITY { $$ = (int) FIELD_ENTITY; }
|
||||
| BYTE { $$ = (int) FIELD_BYTE; }
|
||||
| VARSTRING { $$ = (int) FIELD_VARSTRING; }
|
||||
;
|
||||
|
||||
objectUseStatement:
|
||||
USE Name Name objectTail
|
||||
{
|
||||
executeUse($2, $3, $4);
|
||||
}
|
||||
| USE Name objectTail
|
||||
{
|
||||
executeUse($2, NULL, $3);
|
||||
}
|
||||
;
|
||||
|
||||
objectTail:
|
||||
'=' expr '{' properties '}'
|
||||
{
|
||||
$$ = buildObjectTail($2, $4);
|
||||
}
|
||||
| '{' properties '}'
|
||||
{
|
||||
$$ = buildObjectTail(NULL, $2);
|
||||
}
|
||||
;
|
||||
|
||||
properties:
|
||||
property
|
||||
{
|
||||
$$ = buildPropertyList(NULL, $1);
|
||||
}
|
||||
| properties property
|
||||
{
|
||||
$$ = buildPropertyList($1, $2);
|
||||
}
|
||||
;
|
||||
|
||||
property:
|
||||
Name ':' exprList
|
||||
{
|
||||
$$ = buildProperty($1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
exprList:
|
||||
expr
|
||||
{
|
||||
$$ = buildExprList(NULL, $1);
|
||||
}
|
||||
| exprList ',' expr
|
||||
{
|
||||
$$ = buildExprList($1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
expr:
|
||||
Name
|
||||
{
|
||||
$$ = buildExpr(ID_EXPR, $1);
|
||||
}
|
||||
| Number
|
||||
{
|
||||
$$ = buildExpr(NUM_EXPR, $1);
|
||||
}
|
||||
| String
|
||||
{
|
||||
$$ = buildExpr(STRING_EXPR, $1);
|
||||
}
|
||||
| BitString
|
||||
{
|
||||
$$ = buildExpr(BITSTRING_EXPR, $1);
|
||||
}
|
||||
| '(' expr ')'
|
||||
{
|
||||
$$ = buildExpr(EXPR_EXPR, $2);
|
||||
}
|
||||
| SUB expr %prec UMINUS
|
||||
{
|
||||
$$ = buildExpr(UNOP_EXPR, UMINUS, $2);
|
||||
}
|
||||
| NOT expr
|
||||
{
|
||||
$$ = buildExpr(UNOP_EXPR, NOT, $2);
|
||||
}
|
||||
| A expr
|
||||
{
|
||||
$$ = buildExpr(UNOP_EXPR, A, $2);
|
||||
}
|
||||
| O expr
|
||||
{
|
||||
$$ = buildExpr(UNOP_EXPR, O, $2);
|
||||
}
|
||||
| R expr
|
||||
{
|
||||
$$ = buildExpr(UNOP_EXPR, R, $2);
|
||||
}
|
||||
| expr ADD expr
|
||||
{
|
||||
$$ = buildExpr(BIN_EXPR, $1, ADD, $3);
|
||||
}
|
||||
| expr SUB expr
|
||||
{
|
||||
$$ = buildExpr(BIN_EXPR, $1, SUB, $3);
|
||||
}
|
||||
| expr MUL expr
|
||||
{
|
||||
$$ = buildExpr(BIN_EXPR, $1, MUL, $3);
|
||||
}
|
||||
| expr DIV expr
|
||||
{
|
||||
$$ = buildExpr(BIN_EXPR, $1, DIV, $3);
|
||||
}
|
||||
| expr MOD expr
|
||||
{
|
||||
$$ = buildExpr(BIN_EXPR, $1, MOD, $3);
|
||||
}
|
||||
| expr AND expr
|
||||
{
|
||||
$$ = buildExpr(BIN_EXPR, $1, AND, $3);
|
||||
}
|
||||
| expr OR expr
|
||||
{
|
||||
$$ = buildExpr(BIN_EXPR, $1, OR, $3);
|
||||
}
|
||||
| expr XOR expr
|
||||
{
|
||||
$$ = buildExpr(BIN_EXPR, $1, XOR, $3);
|
||||
}
|
||||
;
|
298
mamelink/griddle/griddleDefs.h
Normal file
298
mamelink/griddle/griddleDefs.h
Normal file
|
@ -0,0 +1,298 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define Case break; case
|
||||
#define Default break; default
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
typedef int boolean;
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define CLASS_REGION 0
|
||||
#define CLASS_DOOR 23
|
||||
#define CLASS_BUILDING 132
|
||||
#define CLASS_FLAT 93
|
||||
#define CLASS_TRAP 87
|
||||
#define CLASS_SUPER_TRAP 92
|
||||
|
||||
/* These constants ought to be extracted from the defines, but they're not.
|
||||
Anytime the definition for the base object changes, these may have to be
|
||||
changed also. */
|
||||
#define IDENT_OFFSET 0
|
||||
#define IDENT_OFFSET_OBJ IDENT_OFFSET
|
||||
#define CONTAINER_OFFSET_OBJ 8
|
||||
#define CONTAINER_TYPE_OFFSET_OBJ 12
|
||||
#define X_OFFSET_OBJ 14
|
||||
#define Y_OFFSET_OBJ 16
|
||||
#define STYLE_OFFSET_OBJ 18
|
||||
#define GRSTATE_OFFSET_OBJ 20
|
||||
#define ORIENT_OFFSET_OBJ 22
|
||||
|
||||
#define TYPE_OFFSET_FLAT 42
|
||||
#define HEIGHT_OFFSET_TRAP 52
|
||||
#define CONNECTION_OFFSET_DOOR 48
|
||||
|
||||
#define CONTAINER_OFFSET_AVA 8
|
||||
#define X_OFFSET_AVA 12
|
||||
#define Y_OFFSET_AVA 14
|
||||
#define GRSTATE_OFFSET_AVA 20
|
||||
#define ORIENT_OFFSET_AVA 28
|
||||
#define STYLE_OFFSET_AVA 32
|
||||
#define PROP_BASE_AVA 80
|
||||
#define AVATAR_PROPERTY_COUNT 6
|
||||
|
||||
#define IDENT_OFFSET_REG IDENT_OFFSET
|
||||
#define LIGHTLEVEL_OFFSET_REG 8
|
||||
#define DEPTH_OFFSET_REG 10
|
||||
#define EAST_OFFSET_REG 12
|
||||
#define WEST_OFFSET_REG 16
|
||||
#define NORTH_OFFSET_REG 20
|
||||
#define SOUTH_OFFSET_REG 24
|
||||
#define CLASSGROUP_OFFSET_REG 28
|
||||
#define ORIENT_OFFSET_REG 30
|
||||
|
||||
typedef enum {
|
||||
VARIABLE_SYM, MACRO_SYM, OBJECT_SYM, NON_SYM, CLASS_SYM
|
||||
} symbolType;
|
||||
|
||||
typedef enum {
|
||||
ID_EXPR, NUM_EXPR, EXPR_EXPR, UNOP_EXPR, BIN_EXPR, STRING_EXPR,
|
||||
BITSTRING_EXPR
|
||||
} exprType;
|
||||
|
||||
typedef enum {
|
||||
FIELD_AVAID, FIELD_BIN15, FIELD_BIN31, FIELD_BIT, FIELD_BYTE,
|
||||
FIELD_CHARACTER, FIELD_ENTITY, FIELD_FATWORD, FIELD_OBJID,
|
||||
FIELD_REGID, FIELD_WORDS, FIELD_VARSTRING
|
||||
} fieldType;
|
||||
|
||||
typedef enum {
|
||||
VAL_UNDEFINED, VAL_INTEGER, VAL_STRING, VAL_AVATAR, VAL_OBJECT,
|
||||
VAL_REGION, VAL_BITSTRING
|
||||
} valueType;
|
||||
|
||||
typedef struct {
|
||||
exprType type;
|
||||
int part1;
|
||||
int part2;
|
||||
int part3;
|
||||
} expression;
|
||||
|
||||
typedef struct exprListStruct {
|
||||
expression *expr;
|
||||
struct exprListStruct *nextExpr;
|
||||
} exprList;
|
||||
|
||||
typedef struct stringListStruct {
|
||||
char *string;
|
||||
struct stringListStruct *nextString;
|
||||
} stringList;
|
||||
|
||||
typedef struct {
|
||||
int value;
|
||||
valueType dataType;
|
||||
} value;
|
||||
|
||||
typedef struct valueListStruct {
|
||||
value *value;
|
||||
struct valueListStruct *nextValue;
|
||||
} valueList;
|
||||
|
||||
typedef struct genericListStruct {
|
||||
int *thing;
|
||||
struct genericListStruct *next;
|
||||
} genericList;
|
||||
|
||||
typedef struct {
|
||||
int *thing;
|
||||
genericList *next;
|
||||
genericList *last;
|
||||
} genericListHead;
|
||||
|
||||
typedef struct {
|
||||
int class;
|
||||
byte *stateVector;
|
||||
} object;
|
||||
|
||||
typedef struct {
|
||||
int class;
|
||||
int id;
|
||||
} objectStub;
|
||||
|
||||
typedef struct objectListStruct {
|
||||
object *object;
|
||||
struct objectListStruct *nextObject;
|
||||
} objectList;
|
||||
|
||||
typedef struct symbolStruct {
|
||||
char *name;
|
||||
int codeNumber;
|
||||
symbolType type;
|
||||
union {
|
||||
value *value;
|
||||
expression *expr;
|
||||
objectStub *object;
|
||||
int class;
|
||||
} def;
|
||||
struct symbolStruct *next;
|
||||
} symbol;
|
||||
|
||||
typedef struct {
|
||||
symbol *fieldName;
|
||||
exprList *data;
|
||||
} property;
|
||||
|
||||
typedef struct propertyListStruct {
|
||||
property *property;
|
||||
struct propertyListStruct *nextProp;
|
||||
} propertyList;
|
||||
|
||||
typedef struct {
|
||||
expression *idExpr;
|
||||
propertyList *properties;
|
||||
} objectTail;
|
||||
|
||||
typedef struct {
|
||||
symbol *name;
|
||||
int dimension;
|
||||
fieldType type;
|
||||
int offset;
|
||||
boolean invisible;
|
||||
exprList *initValues;
|
||||
} field;
|
||||
|
||||
typedef struct fieldListStruct {
|
||||
field *field;
|
||||
struct fieldListStruct *nextField;
|
||||
} fieldList;
|
||||
|
||||
typedef struct {
|
||||
fieldList *fields;
|
||||
int size;
|
||||
symbol *className;
|
||||
byte *prototype;
|
||||
} classDescriptor;
|
||||
|
||||
#define HASH_MAX 512
|
||||
symbol *symbolTable[HASH_MAX];
|
||||
|
||||
char *malloc();
|
||||
|
||||
#define typeAlloc(t) ((t *)malloc(sizeof(t)))
|
||||
#define typeAllocMulti(t,n) ((t *)malloc((n)*sizeof(t)))
|
||||
#define byteAlloc(n) ((byte *)malloc(n))
|
||||
|
||||
typedef struct fileListStruct {
|
||||
FILE *fyle;
|
||||
struct fileListStruct *next;
|
||||
int saveLine;
|
||||
char *saveName;
|
||||
} fileList;
|
||||
|
||||
fileList *inputStack;
|
||||
fileList *bottomOfInputStack;
|
||||
FILE *currentInput;
|
||||
int currentLineNumber;
|
||||
char *currentFileName;
|
||||
int globalIdCounter;
|
||||
int globalIdAdjustment;
|
||||
int objectBase;
|
||||
|
||||
FILE *griFile;
|
||||
FILE *rawFile;
|
||||
FILE *cvFile;
|
||||
FILE *indirFile;
|
||||
int indirectPass;
|
||||
stringList *cvInput;
|
||||
char *classFileName;
|
||||
boolean debug;
|
||||
boolean testMode;
|
||||
boolean assignRelativeIds;
|
||||
int useStartCount;
|
||||
boolean insideDefinition;
|
||||
boolean announceIncludes;
|
||||
|
||||
#define MAXCLASS 256
|
||||
classDescriptor *classDefs[MAXCLASS+1];
|
||||
|
||||
#define MAXNOID 256
|
||||
int objectCount;
|
||||
int rawCount;
|
||||
object *noidArray[MAXNOID];
|
||||
object *altNoidArray[MAXNOID];
|
||||
boolean noidAlive[MAXNOID];
|
||||
boolean fredModeLexing;
|
||||
char *fredLexString;
|
||||
|
||||
boolean promptDefault;
|
||||
char pathname[80];
|
||||
char regionName[80];
|
||||
byte cv[512];
|
||||
int cvLength;
|
||||
int displayNoid;
|
||||
object *undeleteBuffer;
|
||||
int previousClass;
|
||||
|
||||
|
||||
/* C64 locations */
|
||||
#define KEYBOARD_OVERRIDE (word)0x0010
|
||||
#define KEYBOARD_KEYPRESS (word)0x0011
|
||||
#define TOUCH_SLOT (word)0x0012
|
||||
#define TOUCHED_OBJECT (word)0x0013
|
||||
#define TOUCHED_ADDRES (word)0x0014
|
||||
#define CREATE_DATA_SLOT (word)0x0801
|
||||
#define CV_SIZE_SLOT (word)0xea07
|
||||
#define CV_DATA_SLOT (word)0xea09
|
||||
|
||||
/* C64 override commands */
|
||||
#define CMD_CREATE 1
|
||||
#define CMD_SAVE_CV 2
|
||||
#define CMD_LOAD_CV 3
|
||||
|
||||
#define TRAP_EDIT_KEY 141
|
||||
#define UPPER_LEFT_KEY 18
|
||||
#define UPPER_RIGHT_KEY 19
|
||||
#define LOWER_LEFT_KEY 20
|
||||
#define LOWER_RIGHT_KEY 21
|
||||
|
||||
#define DEL '\177'
|
||||
#define ESCAPE '\033'
|
||||
#define ctrl(c) ('c'&0x1F)
|
||||
#define CTRL_C ctrl(C)
|
||||
#define CTRL_U ctrl(U)
|
||||
|
||||
#define mvclrtobot(y,x) { move((y),(x)); clrtobot(); }
|
||||
#define mvclrtoeol(y,x) { move((y),(x)); clrtoeol(); }
|
||||
#define clearDisplay() mvclrtobot(1,0)
|
||||
#define nextlc(line,col,dy) {++(line);if((line)>LINES-1){\
|
||||
(line)=1;(col)+=(dy);}}
|
||||
|
||||
#define myCont() if (!testMode) Cont();
|
||||
|
||||
#define fredModeLexingOn() fredModeLexing = TRUE;
|
||||
#define fredModeLexingOff() { strcpy(fredLexString, "\n"); \
|
||||
yylex(); fredModeLexing = FALSE; }
|
||||
|
||||
#define isAvatar(n) (noidArray[(n)]->class == 0)
|
||||
|
||||
typedef struct {
|
||||
int west;
|
||||
int north;
|
||||
int east;
|
||||
int south;
|
||||
int rot;
|
||||
int *multi;
|
||||
int multiCount;
|
||||
int region;
|
||||
} indirectEntry;
|
||||
|
||||
indirectEntry *indirTable;
|
||||
int indirCount;
|
||||
char indirName[80];
|
||||
int indirArgc;
|
||||
char *indirArgv[50];
|
||||
int indirRegion;
|
||||
boolean sortObjects;
|
344
mamelink/griddle/indir.c
Normal file
344
mamelink/griddle/indir.c
Normal file
|
@ -0,0 +1,344 @@
|
|||
#include "griddleDefs.h"
|
||||
|
||||
#define MAXLINE 500
|
||||
|
||||
char *
|
||||
scan_number(args, resultptr)
|
||||
char *args;
|
||||
int *resultptr;
|
||||
{
|
||||
*resultptr = 0;
|
||||
while ('0' <= *args && *args <= '9')
|
||||
*resultptr = *resultptr * 10 + *args++ - '0';
|
||||
return(args);
|
||||
}
|
||||
|
||||
char *
|
||||
scan_connections(args, multiOK, resultptr, multiptr, countptr)
|
||||
char *args;
|
||||
boolean multiOK;
|
||||
int *resultptr;
|
||||
int **multiptr;
|
||||
int *countptr;
|
||||
{
|
||||
int multiArray[20];
|
||||
int multiCount;
|
||||
int dummy;
|
||||
int i;
|
||||
|
||||
if (*args == '(') {
|
||||
*args = ' ';
|
||||
multiCount = 0;
|
||||
while (*args == ' ')
|
||||
args = scan_number(args+1, &multiArray[multiCount++]);
|
||||
*resultptr = multiArray[multiCount - 1];
|
||||
if (multiOK) {
|
||||
*multiptr = typeAllocMulti(int, multiCount);
|
||||
for (i=0; i<multiCount; ++i)
|
||||
(*multiptr)[i] = multiArray[i];
|
||||
*countptr = multiCount;
|
||||
}
|
||||
return(args + 1);
|
||||
} else {
|
||||
args = scan_number(args, resultptr);
|
||||
if (multiOK) {
|
||||
*multiptr = typeAlloc(int);
|
||||
(*multiptr)[0] = *resultptr;
|
||||
*countptr = 1;
|
||||
}
|
||||
return(args);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
scanIndirectFilePass1()
|
||||
{
|
||||
char line[MAXLINE];
|
||||
char *argptr;
|
||||
char *iptr;
|
||||
char *index();
|
||||
char *skipArg();
|
||||
boolean stringFlag;
|
||||
int rot;
|
||||
|
||||
indirRegion = 0;
|
||||
indirectPass = 1;
|
||||
while (fgets(line, MAXLINE, indirFile) != NULL) {
|
||||
iptr = indirName;
|
||||
argptr = line;
|
||||
while (*argptr != ' ')
|
||||
*iptr++ = *argptr++;
|
||||
*iptr = '\0';
|
||||
|
||||
argptr += 3;
|
||||
argptr = scan_number(argptr, &rot);
|
||||
indirTable[indirRegion].rot = rot;
|
||||
argptr = scan_connections(argptr + 3, rot == 0,
|
||||
&indirTable[indirRegion].west,
|
||||
&indirTable[indirRegion].multi,
|
||||
&indirTable[indirRegion].multiCount);
|
||||
argptr = scan_connections(argptr + 3, rot == 1,
|
||||
&indirTable[indirRegion].north,
|
||||
&indirTable[indirRegion].multi,
|
||||
&indirTable[indirRegion].multiCount);
|
||||
argptr = scan_connections(argptr + 3, rot == 2,
|
||||
&indirTable[indirRegion].east,
|
||||
&indirTable[indirRegion].multi,
|
||||
&indirTable[indirRegion].multiCount);
|
||||
argptr = scan_connections(argptr + 3, rot == 3,
|
||||
&indirTable[indirRegion].south,
|
||||
&indirTable[indirRegion].multi,
|
||||
&indirTable[indirRegion].multiCount);
|
||||
argptr = index(argptr, '/') + 1;
|
||||
indirArgc = 0;
|
||||
while (argptr != NULL && *argptr != '\0' && *argptr != '\n') {
|
||||
while (*argptr == ' ')
|
||||
++argptr;
|
||||
if (stringFlag = (*argptr == '"'))
|
||||
++argptr;
|
||||
indirArgv[indirArgc++] = argptr;
|
||||
argptr = skipArg(argptr, stringFlag);
|
||||
if (argptr != NULL)
|
||||
*argptr++ = '\0';
|
||||
}
|
||||
queueInputFile(strcat(indirName, ".gri"));
|
||||
if (!openFirstFile(FALSE)) {
|
||||
error("can't continue from here!");
|
||||
exit(1);
|
||||
}
|
||||
globalIdAdjustment = globalIdCounter - 1001;
|
||||
yyparse();
|
||||
++indirRegion;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
scanIndirectFilePass2()
|
||||
{
|
||||
char line[MAXLINE];
|
||||
char *argptr;
|
||||
char *iptr;
|
||||
char *index();
|
||||
char *skipArg();
|
||||
boolean stringFlag;
|
||||
int dummy;
|
||||
|
||||
indirRegion = 0;
|
||||
indirectPass = 2;
|
||||
globalIdCounter = 1001;
|
||||
while (fgets(line, MAXLINE, indirFile) != NULL) {
|
||||
iptr = indirName;
|
||||
argptr = line;
|
||||
while (*argptr != ' ')
|
||||
*iptr++ = *argptr++;
|
||||
*iptr = '\0';
|
||||
|
||||
argptr += 3;
|
||||
argptr = scan_number(argptr, &dummy);
|
||||
argptr = scan_connections(argptr, FALSE, &dummy, NULL,&dummy);
|
||||
argptr = scan_connections(argptr, FALSE, &dummy, NULL,&dummy);
|
||||
argptr = scan_connections(argptr, FALSE, &dummy, NULL,&dummy);
|
||||
argptr = scan_connections(argptr, FALSE, &dummy, NULL,&dummy);
|
||||
argptr = index(argptr, '/') + 1;
|
||||
indirArgc = 0;
|
||||
while (argptr != NULL && *argptr != '\0' && *argptr != '\n') {
|
||||
while (*argptr == ' ')
|
||||
++argptr;
|
||||
if (stringFlag = (*argptr == '"'))
|
||||
++argptr;
|
||||
indirArgv[indirArgc++] = argptr;
|
||||
argptr = skipArg(argptr, stringFlag);
|
||||
if (argptr != NULL)
|
||||
*argptr++ = '\0';
|
||||
|
||||
}
|
||||
queueInputFile(strcat(indirName, ".gri"));
|
||||
if (!openFirstFile(FALSE)) {
|
||||
error("can't continue from here!");
|
||||
exit(1);
|
||||
}
|
||||
globalIdAdjustment = globalIdCounter - 1001;
|
||||
yyparse();
|
||||
++indirRegion;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
replaceIndirectArgs(obj, index)
|
||||
object *obj;
|
||||
int index;
|
||||
{
|
||||
int i;
|
||||
byte *buf;
|
||||
int reg;
|
||||
|
||||
reg = indirRegion - 1;
|
||||
buf = obj->stateVector;
|
||||
if (obj->class == CLASS_REGION) {
|
||||
fillLong(buf, WEST_OFFSET_REG,
|
||||
getIdent(indirTable[reg].west));
|
||||
fillLong(buf, NORTH_OFFSET_REG,
|
||||
getIdent(indirTable[reg].north));
|
||||
fillLong(buf, EAST_OFFSET_REG,
|
||||
getIdent(indirTable[reg].east));
|
||||
fillLong(buf, SOUTH_OFFSET_REG,
|
||||
getIdent(indirTable[reg].south));
|
||||
fillWord(buf, ORIENT_OFFSET_REG, indirTable[reg].rot);
|
||||
} else if (obj->class == CLASS_DOOR || obj->class == CLASS_BUILDING) {
|
||||
if (index <= indirTable[reg].multiCount) {
|
||||
fillLong(buf, CONNECTION_OFFSET_DOOR,
|
||||
getIdent(indirTable[reg].multi[index-1]));
|
||||
if (index == indirTable[reg].multiCount) {
|
||||
buf = altNoidArray[0]->stateVector;
|
||||
switch (indirTable[reg].rot) {
|
||||
Case 0: fillLong(buf, WEST_OFFSET_REG, -1);
|
||||
Case 1: fillLong(buf, NORTH_OFFSET_REG, -1);
|
||||
Case 2: fillLong(buf, EAST_OFFSET_REG, -1);
|
||||
Case 3: fillLong(buf, SOUTH_OFFSET_REG, -1);
|
||||
}
|
||||
}
|
||||
} else
|
||||
fillLong(buf, CONNECTION_OFFSET_DOOR, -1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getIdent(num)
|
||||
int num;
|
||||
{
|
||||
if (num == 0)
|
||||
return(-1);
|
||||
else
|
||||
return(indirTable[num - 1].region);
|
||||
}
|
||||
|
||||
char *
|
||||
skipArg(line, stringFlag)
|
||||
char *line;
|
||||
boolean stringFlag;
|
||||
{
|
||||
char *index();
|
||||
|
||||
if (stringFlag) {
|
||||
while ((line = index(line+1, '"')) != NULL)
|
||||
if (*(line - 1) != '\\')
|
||||
return(line);
|
||||
} else for (; *line != ' ' && *line != '\n' && *line != '\0'; ++line)
|
||||
;
|
||||
return(line);
|
||||
}
|
||||
|
||||
void
|
||||
replaceParams(line)
|
||||
char *line;
|
||||
{
|
||||
char scratchBuf[500];
|
||||
char *outptr;
|
||||
char *argptr;
|
||||
char *inptr;
|
||||
int offset;
|
||||
enum { LEFT, CENTER, RIGHT, NONE } format;
|
||||
int width;
|
||||
int i;
|
||||
int len;
|
||||
|
||||
outptr = scratchBuf;
|
||||
inptr = line;
|
||||
while (*inptr != '\0') {
|
||||
if (*inptr == '`') {
|
||||
offset = scanNumber(&inptr);
|
||||
if (*inptr == 'l' || *inptr == 'r' || *inptr == 'c') {
|
||||
format = (*inptr == 'l') ? LEFT :
|
||||
((*inptr == 'r') ? RIGHT : CENTER);
|
||||
width = scanNumber(&inptr) + 1;
|
||||
} else
|
||||
format = NONE;
|
||||
if (indirArgc < offset)
|
||||
error("parameter offset %d out of range\n",
|
||||
offset);
|
||||
else if (offset == -1)
|
||||
*outptr++ = '`';
|
||||
else {
|
||||
len = strlen(indirArgv[offset]);
|
||||
switch (format) {
|
||||
Case NONE:
|
||||
for (argptr=indirArgv[offset];
|
||||
*argptr != '\0'; )
|
||||
*outptr++ = *argptr++;
|
||||
Case LEFT:
|
||||
for (argptr=indirArgv[offset], i=0;
|
||||
*argptr != '\0' &&
|
||||
i < width; ++i)
|
||||
*outptr++ = *argptr++;
|
||||
for (; i < width; ++i)
|
||||
*outptr++ = ' ';
|
||||
|
||||
Case RIGHT:
|
||||
argptr = indirArgv[offset];
|
||||
if (len < width)
|
||||
for (i=width-len; i > 0; --i)
|
||||
*outptr++ = ' ';
|
||||
else
|
||||
argptr += len - width;
|
||||
while (*argptr != '\0')
|
||||
*outptr++ = *argptr++;
|
||||
|
||||
Case CENTER:
|
||||
argptr = indirArgv[offset];
|
||||
i = 0;
|
||||
if (len < width)
|
||||
for (; i < (width-len)/2; ++i)
|
||||
*outptr++ = ' ';
|
||||
else
|
||||
argptr += (len - width) / 2;
|
||||
for (; i<width && *argptr!='\0'; ++i)
|
||||
*outptr++ = *argptr++;
|
||||
for (; i<width; ++i)
|
||||
*outptr++ = ' ';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (*inptr == '\\') {
|
||||
++inptr;
|
||||
if (*inptr != '`')
|
||||
*outptr++ = '\\';
|
||||
}
|
||||
*outptr++ = *inptr++;
|
||||
}
|
||||
}
|
||||
*outptr = '\0';
|
||||
strcpy(line, scratchBuf);
|
||||
}
|
||||
|
||||
int
|
||||
scanNumber(lineptr)
|
||||
char **lineptr;
|
||||
{
|
||||
int result;
|
||||
char *line;
|
||||
|
||||
result = 0;
|
||||
line = *lineptr + 1;
|
||||
while ('0' <= *line && *line <= '9')
|
||||
result = result * 10 + *line++ - '0';
|
||||
*lineptr = line;
|
||||
return(result - 1);
|
||||
}
|
||||
|
||||
void
|
||||
indirectGriddle()
|
||||
{
|
||||
char line[80];
|
||||
int i;
|
||||
|
||||
fgets(line, 80, indirFile);
|
||||
sscanf(line, "%d", &indirCount);
|
||||
indirTable = typeAllocMulti(indirectEntry, indirCount);
|
||||
scanIndirectFilePass1();
|
||||
|
||||
rewind(indirFile);
|
||||
flushNoidArray();
|
||||
fgets(line, 80, indirFile);
|
||||
scanIndirectFilePass2();
|
||||
flushNoidArray();
|
||||
}
|
594
mamelink/griddle/lexer.c
Normal file
594
mamelink/griddle/lexer.c
Normal file
|
@ -0,0 +1,594 @@
|
|||
#include "griddleDefs.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
extern int yylval;
|
||||
int yydebug;
|
||||
|
||||
typedef enum {
|
||||
C_SKIP, C_ZERO, C_DIG, C_ALPH, C_QUOTE, C_APOSTROPHE, C_LIT, C_SLASH,
|
||||
C_NL
|
||||
} charType;
|
||||
|
||||
static charType char_type[128] = {
|
||||
/* EOF Soh Stx Etx Eot Enq Ack Bell */
|
||||
/* 0 */ C_LIT, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP,
|
||||
/* Backsp HTab Newline VTab Newpage Return So Si */
|
||||
/* 8 */ C_SKIP, C_SKIP, C_NL, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP,
|
||||
/* Dle Dc1 Dc2 Dc3 Dc4 Nak Syn Etb */
|
||||
/* 16 */ C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP,
|
||||
/* Can Em Sub Escape Fs Gs Rs Us */
|
||||
/* 24 */ C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP, C_SKIP,
|
||||
/* Space ! " # $ % & ' */
|
||||
/* 32 */ C_SKIP, C_SKIP, C_QUOTE, C_LIT, C_SKIP, C_LIT, C_LIT, C_APOSTROPHE,
|
||||
/* ( ) * + , - . / */
|
||||
/* 40 */ C_LIT, C_LIT, C_LIT, C_LIT, C_LIT, C_LIT, C_SKIP, C_SLASH,
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
/* 48 */ C_DIG, C_DIG, C_DIG, C_DIG, C_DIG, C_DIG, C_DIG, C_DIG,
|
||||
/* 8 9 : ; < = > ? */
|
||||
/* 56 */ C_DIG, C_DIG, C_LIT, C_SKIP, C_SKIP, C_LIT, C_SKIP, C_SKIP,
|
||||
/* @ A B C D E F G */
|
||||
/* 64 */ C_SKIP, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH,
|
||||
/* H I J J L M N O */
|
||||
/* 72 */ C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH,
|
||||
/* P Q R S T U V W */
|
||||
/* 80 */ C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH,
|
||||
/* X Y Z [ \ ] ^ _ */
|
||||
/* 88 */ C_ALPH, C_ALPH, C_ALPH, C_SKIP, C_SKIP, C_SKIP, C_LIT, C_ALPH,
|
||||
/* ` a b c d e f g */
|
||||
/* 96 */ C_SKIP, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH,
|
||||
/* h i j k l m n o */
|
||||
/*104 */ C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH,
|
||||
/* p q r s t u v w */
|
||||
/*112 */ C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH, C_ALPH,
|
||||
/* x y z { | } ` Del */
|
||||
/*120 */ C_ALPH, C_ALPH, C_ALPH, C_LIT, C_LIT, C_LIT, C_SKIP, C_SKIP
|
||||
};
|
||||
|
||||
static int litCode[128] = {
|
||||
/* EOF Soh Stx Etx Eot Enq Ack Bell */
|
||||
/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* Backsp HTab Newline VTab Newpage Return So Si */
|
||||
/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* Dle Dc1 Dc2 Dc3 Dc4 Nak Syn Etb */
|
||||
/* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* Can Em Sub Escape Fs Gs Rs Us */
|
||||
/* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* Space ! " # $ % & ' */
|
||||
/* 32 */ 0, 0, 0, '#', 0, MOD, AND, 0,
|
||||
/* ( ) * + , - . / */
|
||||
/* 40 */ '(', ')', MUL, ADD, ',', SUB, 0, 0,
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
/* 48 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 8 9 : ; < = > ? */
|
||||
/* 56 */ 0, 0, ':', 0, 0, '=', 0, 0,
|
||||
/* @ A B C D E F G */
|
||||
/* 64 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* H I J J L M N O */
|
||||
/* 72 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* P Q R S T U V W */
|
||||
/* 80 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* X Y Z [ \ ] ^ _ */
|
||||
/* 88 */ 0, 0, 0, 0, 0, 0, XOR, 0,
|
||||
/* ` a b c d e f g */
|
||||
/* 96 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* h i j k l m n o */
|
||||
/*104 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* p q r s t u v w */
|
||||
/*112 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* x y z { | } ` Del */
|
||||
/*120 */ 0, 0, 0, '{', OR, '}', 0, 0
|
||||
};
|
||||
|
||||
static boolean newline = TRUE;
|
||||
static boolean oldnewline;
|
||||
|
||||
char yytext[256];
|
||||
|
||||
yylex()
|
||||
{
|
||||
char c;
|
||||
|
||||
for (;;) {
|
||||
c = input();
|
||||
oldnewline = newline;
|
||||
newline = FALSE;
|
||||
switch (char_type[c]) {
|
||||
Case C_SLASH:
|
||||
if (oldnewline) {
|
||||
parseRawline();
|
||||
return(Rawline);
|
||||
}
|
||||
c = input();
|
||||
if (c == '*')
|
||||
comment();
|
||||
else {
|
||||
unput(c);
|
||||
return(DIV);
|
||||
}
|
||||
|
||||
Case C_ZERO:
|
||||
c = input();
|
||||
if (c == 'x' || c == 'X')
|
||||
parseNumber(16, input());
|
||||
else if (c == 'b' || c == 'B')
|
||||
parseNumber(2, input());
|
||||
else if (c == 'q' || c == 'Q')
|
||||
parseNumber(4, input());
|
||||
else
|
||||
parseNumber(8, c);
|
||||
return(Number);
|
||||
|
||||
Case C_DIG:
|
||||
parseNumber(10, c);
|
||||
return(Number);
|
||||
|
||||
Case C_ALPH:
|
||||
parseName(c);
|
||||
if ((yylval = matchKeyword(yytext)) != 0)
|
||||
return(yylval);
|
||||
yylval = lookupSymbol(yytext);
|
||||
/* if (debug)
|
||||
printf("lexer: Name '%s'\n", yytext);*/
|
||||
return(Name);
|
||||
|
||||
Case C_QUOTE:
|
||||
lexString('"');
|
||||
string();
|
||||
return(String);
|
||||
|
||||
Case C_APOSTROPHE:
|
||||
lexString('\'');
|
||||
c = input();
|
||||
if (c == 'b' || c == 'B') {
|
||||
bitString();
|
||||
return(BitString);
|
||||
} else {
|
||||
string();
|
||||
unput(c);
|
||||
return(String);
|
||||
}
|
||||
|
||||
Case C_LIT:
|
||||
return(litCode[c]);
|
||||
|
||||
Case C_NL:
|
||||
newline = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseName(c)
|
||||
char c;
|
||||
{
|
||||
char *cptr;
|
||||
|
||||
cptr = yytext;
|
||||
while (char_type[c] == C_DIG || char_type[c] == C_ALPH) {
|
||||
*cptr++ = c;
|
||||
c = input();
|
||||
}
|
||||
*cptr = '\0';
|
||||
unput(c);
|
||||
}
|
||||
|
||||
comment()
|
||||
{
|
||||
char c, c1;
|
||||
|
||||
loop:
|
||||
while ((c = input()) != '*' && c != 0)
|
||||
;
|
||||
|
||||
if ((c1 = input()) != '/' && c != 0)
|
||||
{
|
||||
unput(c1);
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
|
||||
parseNumber(base, c)
|
||||
int base;
|
||||
char c;
|
||||
{
|
||||
yylval = 0;
|
||||
while (isDigit(c, base)) {
|
||||
yylval = yylval * base + digitValue(c);
|
||||
c = input();
|
||||
}
|
||||
unput(c);
|
||||
/* if (debug)
|
||||
printf("lexer: Number (%d) = %d\n", base, yylval);*/
|
||||
}
|
||||
|
||||
skipToEol()
|
||||
{
|
||||
char c;
|
||||
|
||||
while ((c = input()) != '\n' && c != 0)
|
||||
;
|
||||
unput(c);
|
||||
}
|
||||
|
||||
int
|
||||
getHexByte()
|
||||
{
|
||||
char c1, c2;
|
||||
|
||||
while ((c1 = input()) == '\\' || c1 == ' ')
|
||||
if (c1 == '\\')
|
||||
c1 = input();
|
||||
if (c1 == '\n' || c1 == 0) {
|
||||
unput(c1);
|
||||
return(-1);
|
||||
} else if (!isDigit(c1, 16)) {
|
||||
error("illegal hex digit '%c'\n", c1);
|
||||
skipToEol();
|
||||
return(-2);
|
||||
}
|
||||
c2 = input();
|
||||
if (c2 == '\n' || c2 == 0) {
|
||||
unput(c1);
|
||||
error("bad hex digit parity\n");
|
||||
return(-2);
|
||||
} else if (!isDigit(c2, 16)) {
|
||||
error("illegal hex digit '%c'\n", c2);
|
||||
skipToEol();
|
||||
return(-2);
|
||||
}
|
||||
return(digitValue(c1) * 16 + digitValue(c2));
|
||||
}
|
||||
|
||||
getHexString(buf, size)
|
||||
byte *buf;
|
||||
int size;
|
||||
{
|
||||
int i;
|
||||
int aByte;
|
||||
char c;
|
||||
|
||||
for (i=0; i<size; ++i) {
|
||||
aByte = getHexByte();
|
||||
if (aByte < 0) break;
|
||||
buf[i] = aByte;
|
||||
}
|
||||
if (aByte < 0) {
|
||||
error("raw line short\n");
|
||||
for (; i<size; ++i)
|
||||
buf[i] = 0;
|
||||
} else if (getHexByte() >= 0) {
|
||||
error("raw line long\n");
|
||||
skipToEol();
|
||||
}
|
||||
}
|
||||
|
||||
parseRawline()
|
||||
{
|
||||
object *result;
|
||||
char hexString[1500];
|
||||
int length;
|
||||
|
||||
result = typeAlloc(object);
|
||||
parseNumber(10, input());
|
||||
result->class = yylval;
|
||||
result->stateVector = (byte *)malloc(classDefs[yylval+1]->size);
|
||||
getHexString(result->stateVector, classDefs[yylval+1]->size);
|
||||
yylval = (int)result;
|
||||
/* if (debug)
|
||||
printf("lexer: Rawline class=%d addr=%x\n", result->class, result);*/
|
||||
}
|
||||
|
||||
boolean
|
||||
isDigit(c, base)
|
||||
char c;
|
||||
int base;
|
||||
{
|
||||
if (base <= 10)
|
||||
return('0' <= c && c <= '0' - 1 + base);
|
||||
else
|
||||
return( ('0' <= c && c <= '9') ||
|
||||
('a' <= c && c <= 'f') ||
|
||||
('A' <= c && c <= 'F') );
|
||||
}
|
||||
|
||||
int
|
||||
digitValue(c)
|
||||
char c;
|
||||
{
|
||||
if ('0'<=c && c<='9')
|
||||
return(c - '0');
|
||||
else if ('a'<=c && c<='f')
|
||||
return(c - 'a' + 10);
|
||||
else
|
||||
return(c - 'A' + 10);
|
||||
}
|
||||
|
||||
#define FORMFEED 12
|
||||
#define HALF_SPACE 128
|
||||
#define DOUBLE_SPACE 143
|
||||
#define INC_WIDTH 129
|
||||
#define DEC_WIDTH 130
|
||||
#define INC_HEIGHT 131
|
||||
#define DEC_HEIGHT 132
|
||||
#define HALF_SIZE 133
|
||||
#define CHAR_RETURN 134
|
||||
#define DN_HALF_CHAR 139
|
||||
#define INVERSE 140
|
||||
#define CURSOR_RIGHT 135
|
||||
#define CURSOR_LEFT 136
|
||||
#define CURSOR_UP 137
|
||||
#define CURSOR_DOWN 138
|
||||
|
||||
static struct {
|
||||
char inChar;
|
||||
char outChar;
|
||||
} escapes[] = {
|
||||
'n', '\n', 't', '\t', 'b', '\b',
|
||||
'r', '\r', 'f', FORMFEED, 'e', ESCAPE,
|
||||
'\\', '\\', '\'', '\'', '"', '"',
|
||||
' ', HALF_SPACE, '#', DOUBLE_SPACE, '+', INC_WIDTH,
|
||||
'-', DEC_WIDTH, '(', INC_HEIGHT, ')', DEC_HEIGHT,
|
||||
'h', HALF_SIZE, 'd', DN_HALF_CHAR, 'i', INVERSE,
|
||||
'>', CURSOR_LEFT, '<', CURSOR_RIGHT, '^', CURSOR_UP,
|
||||
'v', CURSOR_DOWN, 'R', CHAR_RETURN, '\0', 0
|
||||
};
|
||||
|
||||
char
|
||||
unescape()
|
||||
{
|
||||
int i;
|
||||
char result;
|
||||
char c;
|
||||
|
||||
c = input();
|
||||
if (c == '^') {
|
||||
result = input() & 0x3F;
|
||||
} else if (c == 'x') {
|
||||
result = 0;
|
||||
for (i=0; i<2; ++i) {
|
||||
c = input();
|
||||
if (isDigit(c, 16))
|
||||
result = result * 16 + digitValue(c);
|
||||
else
|
||||
unput(c);
|
||||
}
|
||||
} else if ('0' <= c && c <= '7') {
|
||||
result = digitValue(c);
|
||||
for (i=0; i<2; ++i) {
|
||||
c = input();
|
||||
if ('0' <= c && c <= '7')
|
||||
result = result * 8 + digitValue(c);
|
||||
else
|
||||
unput(c);
|
||||
}
|
||||
} else for (i=0; escapes[i].inChar!='\0'; ++i) {
|
||||
result = c;
|
||||
if (c == escapes[i].inChar) {
|
||||
result = escapes[i].outChar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
char *
|
||||
escape(c)
|
||||
char c;
|
||||
{
|
||||
int i;
|
||||
static char result[5];
|
||||
|
||||
if (' ' <= c && c <= '~')
|
||||
sprintf(result, "%c", c);
|
||||
else if (c == 0)
|
||||
sprintf(result, "\\0");
|
||||
else {
|
||||
sprintf(result, "\\%o", (byte)c);
|
||||
for (i=0; escapes[i].outChar!='\0'; ++i)
|
||||
if (c == escapes[i].outChar) {
|
||||
sprintf(result, "\\%c", escapes[i].inChar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
lexString(end)
|
||||
char end;
|
||||
{
|
||||
char *str;
|
||||
char c;
|
||||
|
||||
str = yytext;
|
||||
for (c = input(); c != end; c = input())
|
||||
if (c == '\\')
|
||||
*str++ = unescape();
|
||||
else
|
||||
*str++ = c;
|
||||
*str = '\0';
|
||||
}
|
||||
|
||||
string()
|
||||
{
|
||||
int len;
|
||||
char *str;
|
||||
char *inptr;
|
||||
|
||||
str = malloc(strlen(yytext) + 1);
|
||||
yylval = (int)str;
|
||||
strcpy(str, yytext);
|
||||
/* if (debug)
|
||||
printf("lexer: String '%s'\n", yylval);*/
|
||||
}
|
||||
|
||||
bitString()
|
||||
{
|
||||
int len;
|
||||
byte *str;
|
||||
int i;
|
||||
|
||||
len = strlen(yytext);
|
||||
str = (byte *)malloc(((len+7) >> 3) + 1);
|
||||
yylval = (int)str;
|
||||
*str++ = len;
|
||||
for (i=0; i<((len+7) >> 3); ++i)
|
||||
str[i] = 0;
|
||||
for (i=0; i<len; ++i)
|
||||
str[i>>3] |= (yytext[i] == '0' ? 0 : 1) << (7 - (i&7));
|
||||
/* if (debug)
|
||||
printf("lexer: BitString, length=%d\n", len);*/
|
||||
}
|
||||
|
||||
static char lineBuf[500] = "";
|
||||
static char *inptr = lineBuf;
|
||||
static char ungot;
|
||||
static boolean ungetFlag = FALSE;
|
||||
|
||||
purgeUnget()
|
||||
{
|
||||
ungetFlag = FALSE;
|
||||
}
|
||||
|
||||
input()
|
||||
{
|
||||
char result;
|
||||
fileList *oldInputStack;
|
||||
|
||||
if (fredModeLexing)
|
||||
return(*fredLexString++);
|
||||
else if (ungetFlag) {
|
||||
ungetFlag = FALSE;
|
||||
return(ungot);
|
||||
}
|
||||
result = *inptr++;
|
||||
if (result == '\0') {
|
||||
if (fgets(lineBuf, 500, currentInput) == NULL) {
|
||||
result = EOF;
|
||||
--inptr;
|
||||
} else {
|
||||
inptr = lineBuf;
|
||||
#ifndef FRED
|
||||
if (indirFile != NULL)
|
||||
replaceParams(lineBuf);
|
||||
#endif
|
||||
result = *inptr++;
|
||||
}
|
||||
}
|
||||
if (result == '\n')
|
||||
++currentLineNumber;
|
||||
else if (result == EOF) {
|
||||
oldInputStack = inputStack;
|
||||
inputStack = inputStack->next;
|
||||
free(oldInputStack);
|
||||
ungetFlag = FALSE;
|
||||
if (announceIncludes) {
|
||||
fprintf(stderr, "<-\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
fclose(currentInput);
|
||||
if (inputStack == NULL) {
|
||||
/* if (debug) printf("in(EOF)\n");*/
|
||||
return(0);
|
||||
} else {
|
||||
currentInput = inputStack->fyle;
|
||||
currentFileName = inputStack->saveName;
|
||||
if (currentInput == NULL) {
|
||||
if (strcmp(inputStack->saveName, "-") == 0) {
|
||||
currentInput = stdin;
|
||||
currentFileName = "<standard input>";
|
||||
} else if ((currentInput = fopen(inputStack->
|
||||
saveName, "r")) == NULL) {
|
||||
systemError("can't open input file %s\n",
|
||||
inputStack->saveName);
|
||||
}
|
||||
inputStack->fyle = currentInput;
|
||||
}
|
||||
currentLineNumber = inputStack->saveLine;
|
||||
return(input());
|
||||
}
|
||||
}
|
||||
/* if (debug) printf("in(%c)\n", result);*/
|
||||
return(result);
|
||||
}
|
||||
|
||||
unput(c)
|
||||
char c;
|
||||
{
|
||||
/* if (debug) printf("un(%c)\n", c);*/
|
||||
if (fredModeLexing)
|
||||
--fredLexString;
|
||||
else {
|
||||
ungetFlag = TRUE;
|
||||
ungot = c;
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
char *string;
|
||||
int token;
|
||||
int minlength;
|
||||
} keywords[] = {
|
||||
/*0*/ "a", A, 0, "ava/id", AVAID, 0,
|
||||
/*2*/ "bin15", BIN15, 0, "bin31", BIN31, 0,
|
||||
/*4*/ "bit", BIT, 0, "byte", BYTE, 0,
|
||||
/*6*/ "ch/aracter", CHARACTER, 0, "de/fine", DEFINE, 0,
|
||||
/*8*/ "endd/efine", ENDDEFINE, 0, "ent/ity", ENTITY, 0,
|
||||
/*10*/ "fat/word", FATWORD, 0, "include", INCLUDE, 0,
|
||||
/*12*/ "int/eger", BIN15, 0, "lo/ng", BIN31, 0,
|
||||
/*14*/ "o", O, 0, "obj/id", OBJID, 0,
|
||||
/*16*/ "r", R, 0, "reg/id", REGID, 0,
|
||||
/*18*/ "use", USE, 0, "var/string", VARSTRING, 0,
|
||||
/*20*/ "wo/rds", WORDS, 0, NULL, 0, 0
|
||||
};
|
||||
|
||||
static int keystart[26] = {
|
||||
/* a */ 0, /* b */ 2, /* c */ 6, /* d */ 7, /* e */ 8,
|
||||
/* f */ 10, /* g */ -1, /* h */ -1, /* i */ 11, /* j */ -1,
|
||||
/* k */ -1, /* l */ 13, /* m */ -1, /* n */ -1, /* o */ 14,
|
||||
/* p */ -1, /* q */ -1, /* r */ 16, /* s */ -1, /* t */ -1,
|
||||
/* u */ 18, /* v */ 19, /* w */ 20, /* x */ -1, /* y */ -1,
|
||||
/* z */ -1 };
|
||||
static int keyend[26] = {
|
||||
/* a */ 1, /* b */ 5, /* c */ 6, /* d */ 7, /* e */ 9,
|
||||
/* f */ 10, /* g */ -1, /* h */ -1, /* i */ 12, /* j */ -1,
|
||||
/* k */ -1, /* l */ 13, /* m */ -1, /* n */ -1, /* o */ 15,
|
||||
/* p */ -1, /* q */ -1, /* r */ 17, /* s */ -1, /* t */ -1,
|
||||
/* u */ 18, /* v */ 19, /* w */ 20, /* x */ -1, /* y */ -1,
|
||||
/* z */ -1 };
|
||||
|
||||
|
||||
setKeywordMinlengths()
|
||||
{
|
||||
char *trailer;
|
||||
char *index();
|
||||
int i;
|
||||
|
||||
for (i = 0; keywords[i].string != NULL; ++i) {
|
||||
trailer = index(keywords[i].string, '/');
|
||||
if (trailer == NULL) {
|
||||
keywords[i].minlength = strlen(keywords[i].string);
|
||||
} else {
|
||||
keywords[i].minlength = trailer - keywords[i].string;
|
||||
strcpy(trailer, trailer + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
matchKeyword(s)
|
||||
char *s;
|
||||
{
|
||||
register int i;
|
||||
register int firstc;
|
||||
int len;
|
||||
|
||||
firstc = *s - 'a';
|
||||
if (firstc < 0 || 25 < firstc || keystart[firstc] == -1)
|
||||
return(0);
|
||||
len = strlen(s);
|
||||
for (i = keystart[firstc]; i <= keyend[firstc]; ++i) {
|
||||
if (len >= keywords[i].minlength &&
|
||||
strncmp(s, keywords[i].string, len) == 0)
|
||||
return(keywords[i].token);
|
||||
}
|
||||
return(0);
|
||||
}
|
355
mamelink/griddle/main.c
Normal file
355
mamelink/griddle/main.c
Normal file
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
griddle -- Ghu's Region Internal Database Description LanguagE
|
||||
*/
|
||||
|
||||
#include "griddleDefs.h"
|
||||
int yydebug;
|
||||
|
||||
#define argcheck(i,m) if (++i >= argc) { error(m); exit(1); }
|
||||
#define argfile(fd,m,t) { \
|
||||
fileName = *args++; \
|
||||
if (strcmp(fileName, "-") == 0) \
|
||||
fd = stdout; \
|
||||
else if ((fd = fopen(fileName, t)) == NULL) \
|
||||
systemError(m, fileName); \
|
||||
}
|
||||
#define argfiler(fd,m) argfile(fd,m,"r")
|
||||
#define argfilew(fd,m) argfile(fd,m,"w")
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
int yyparse();
|
||||
boolean initialize();
|
||||
|
||||
if (!initialize(argc, argv))
|
||||
exit(1);
|
||||
#ifndef FRED
|
||||
if (indirFile == NULL)
|
||||
yyparse();
|
||||
else
|
||||
indirectGriddle();
|
||||
#else
|
||||
yyparse();
|
||||
#endif
|
||||
readClassFile();
|
||||
#ifndef FRED
|
||||
while (cvInput != NULL) {
|
||||
inputContentsVector(cvInput->string);
|
||||
cvInput = cvInput->nextString;
|
||||
}
|
||||
if (cvFile != NULL)
|
||||
outputContentsVector();
|
||||
#else
|
||||
doFredStuff();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
resetRegionCounters()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<objectCount; ++i) {
|
||||
if (noidArray[i] != NULL) {
|
||||
freeObject(noidArray[i]);
|
||||
noidArray[i] = NULL;
|
||||
}
|
||||
}
|
||||
globalIdCounter = 1001;
|
||||
objectCount = 0;
|
||||
rawCount = 0;
|
||||
useStartCount = 0;
|
||||
}
|
||||
|
||||
boolean
|
||||
initialize(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
char **args;
|
||||
char *arg;
|
||||
boolean inputFilesGiven;
|
||||
char *defineFileName;
|
||||
char *fileName;
|
||||
|
||||
char *getenv();
|
||||
void queueInputFile();
|
||||
boolean openFirstFile();
|
||||
stringList *buildStringList();
|
||||
|
||||
griFile = NULL;
|
||||
rawFile = NULL;
|
||||
indirFile = NULL;
|
||||
cvFile = NULL;
|
||||
cvInput = NULL;
|
||||
fredModeLexing = FALSE;
|
||||
debug = FALSE;
|
||||
yydebug = FALSE;
|
||||
testMode = FALSE;
|
||||
objectBase = 0;
|
||||
sortObjects = FALSE;
|
||||
insideDefinition = FALSE;
|
||||
objectCount = 0;
|
||||
resetRegionCounters();
|
||||
inputStack = NULL;
|
||||
announceIncludes = FALSE;
|
||||
inputFilesGiven = FALSE;
|
||||
assignRelativeIds = FALSE;
|
||||
indirectPass = 0;
|
||||
setKeywordMinlengths();
|
||||
|
||||
for (i=0; i<MAXCLASS+1; ++i)
|
||||
classDefs[i] = NULL;
|
||||
|
||||
args = argv + 1;
|
||||
if ((defineFileName = getenv("GHUDEFINES")) == NULL)
|
||||
queueInputFile("/u0/habitat/defines.ghu");
|
||||
else
|
||||
queueInputFile(defineFileName);
|
||||
if ((classFileName = getenv("CLASSINFO")) == NULL)
|
||||
classFileName = "/u0/habitat/class.dat";
|
||||
for (i=1; i<argc; i++) {
|
||||
arg = *args++;
|
||||
if (*arg != '-') {
|
||||
#ifndef FRED
|
||||
queueInputFile(arg);
|
||||
inputFilesGiven = TRUE;
|
||||
continue;
|
||||
#else
|
||||
error("illegal parameter '%s'\n", arg);
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
for (j=1; arg[j]!='\0'; j++) switch (arg[j]) {
|
||||
case 'D':
|
||||
debug = TRUE;
|
||||
continue;
|
||||
|
||||
case 'I':
|
||||
announceIncludes = TRUE;
|
||||
continue;
|
||||
|
||||
case 'R':
|
||||
assignRelativeIds = TRUE;
|
||||
continue;
|
||||
#ifndef FRED
|
||||
case 'c':
|
||||
argcheck(i, "no cv output file name after -c\n");
|
||||
argfilew(cvFile, "can't open cv file %s\n");
|
||||
continue;
|
||||
|
||||
case 'v':
|
||||
argcheck(i, "no cv input file name after -v\n");
|
||||
cvInput = buildStringList(cvInput, *args++);
|
||||
continue;
|
||||
|
||||
case 'g':
|
||||
case 'l':
|
||||
argcheck(i,"no gri file name after -g\n");
|
||||
argfilew(griFile, "can't open gri output file %s\n");
|
||||
continue;
|
||||
|
||||
case 'i':
|
||||
argcheck(i, "no indirect file name after -i\n");
|
||||
argfiler(indirFile, "can't open indirect file %s\n");
|
||||
continue;
|
||||
|
||||
case 'r':
|
||||
case 'o':
|
||||
argcheck(i,"no raw file name after -r\n");
|
||||
argfilew(rawFile, "can't open raw output file %s\n");
|
||||
continue;
|
||||
#endif
|
||||
case 'Y':
|
||||
yydebug = TRUE;
|
||||
continue;
|
||||
|
||||
case 't':
|
||||
testMode = TRUE;
|
||||
continue;
|
||||
|
||||
default:
|
||||
error("bad command line flag -%c\n", arg[j]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#ifndef FRED
|
||||
if(inputFilesGiven && indirFile != NULL) {
|
||||
error("input files and indirect file given at the same time");
|
||||
exit(1);
|
||||
} if (!inputFilesGiven && cvInput == NULL && indirFile == NULL)
|
||||
queueInputFile("-");
|
||||
#endif
|
||||
|
||||
for (i=0; i<MAXNOID; ++i)
|
||||
noidArray[i] = NULL;
|
||||
if (indirFile == NULL)
|
||||
return(openFirstFile(FALSE));
|
||||
}
|
||||
|
||||
int
|
||||
hash(s)
|
||||
char *s;
|
||||
{
|
||||
int result;
|
||||
|
||||
result = 0;
|
||||
while (*s != '\0')
|
||||
result = (result << 1) ^ *s++;
|
||||
return(result & (HASH_MAX - 1));
|
||||
}
|
||||
|
||||
symbol *
|
||||
insertSymbol(name)
|
||||
char *name;
|
||||
{
|
||||
symbol *newSymbol;
|
||||
int hashval;
|
||||
symbol *mptr;
|
||||
symbol *oldmptr;
|
||||
int cmp;
|
||||
|
||||
newSymbol = typeAlloc(symbol);
|
||||
newSymbol->name = malloc(strlen(name) + 1);
|
||||
newSymbol->type = NON_SYM;
|
||||
newSymbol->codeNumber = 0;
|
||||
strcpy(newSymbol->name, name);
|
||||
hashval = hash(name);
|
||||
mptr = symbolTable[hashval];
|
||||
oldmptr = NULL;
|
||||
while (mptr != NULL) {
|
||||
if ((cmp = strcmp(name, mptr->name)) == 0) {
|
||||
error("Hey, symbol %s already in table!", name);
|
||||
exit(1);
|
||||
} else if (cmp > 0) {
|
||||
break;
|
||||
} else {
|
||||
oldmptr = mptr;
|
||||
mptr = mptr->next;
|
||||
}
|
||||
}
|
||||
if (oldmptr == NULL)
|
||||
symbolTable[hashval] = newSymbol;
|
||||
else
|
||||
oldmptr->next = newSymbol;
|
||||
newSymbol->next = mptr;
|
||||
return(newSymbol);
|
||||
}
|
||||
|
||||
symbol *
|
||||
lookupSymbol(name)
|
||||
char *name;
|
||||
{
|
||||
symbol *result;
|
||||
int cmp;
|
||||
|
||||
result = symbolTable[hash(name)];
|
||||
while (result != NULL) {
|
||||
if ((cmp = strcmp(name, result->name)) == 0)
|
||||
return(result);
|
||||
else if (cmp > 0)
|
||||
result = NULL;
|
||||
else
|
||||
result = result->next;
|
||||
}
|
||||
return(insertSymbol(name));
|
||||
}
|
||||
|
||||
void
|
||||
yyerror(s)
|
||||
char *s;
|
||||
{
|
||||
error("\"%s\", line %d: %s\n", currentFileName, currentLineNumber, s);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
queueInputFile(name)
|
||||
char *name;
|
||||
{
|
||||
fileList *newFileName;
|
||||
|
||||
newFileName = typeAlloc(fileList);
|
||||
newFileName->saveName = name;
|
||||
newFileName->fyle = NULL;
|
||||
newFileName->next = NULL;
|
||||
newFileName->saveLine = 1;
|
||||
if (inputStack == NULL) {
|
||||
inputStack = bottomOfInputStack = newFileName;
|
||||
} else {
|
||||
bottomOfInputStack->next = newFileName;
|
||||
bottomOfInputStack = newFileName;
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
openFirstFile(fredMode)
|
||||
boolean fredMode;
|
||||
{
|
||||
if (inputStack == NULL || strcmp(inputStack->saveName, "-") == 0) {
|
||||
inputStack = typeAlloc(fileList);
|
||||
inputStack->saveName = "<standard input>";
|
||||
inputStack->fyle = stdin;
|
||||
inputStack->saveLine = 1;
|
||||
inputStack->next = NULL;
|
||||
} else {
|
||||
if ((inputStack->fyle = fopen(inputStack->saveName,
|
||||
"r")) == NULL) {
|
||||
if (!fredMode)
|
||||
error("can't open input file %s\n",
|
||||
inputStack->saveName);
|
||||
free(inputStack);
|
||||
inputStack = NULL;
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
currentInput = inputStack->fyle;
|
||||
currentLineNumber = inputStack->saveLine;
|
||||
currentFileName = inputStack->saveName;
|
||||
purgeUnget();
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
error(msg, arg1, arg2, arg3)
|
||||
char *msg;
|
||||
int arg1, arg2, arg3;
|
||||
{
|
||||
fprintf(stderr, "error: ");
|
||||
fprintf(stderr, msg, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
systemError(msg, arg1, arg2, arg3)
|
||||
char *msg;
|
||||
int arg1, arg2, arg3;
|
||||
{
|
||||
error(msg, arg1, arg2, arg3);
|
||||
perror("Unix says");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
translate(s, c1, c2)
|
||||
char *s;
|
||||
char c1;
|
||||
char c2;
|
||||
{
|
||||
for (; *s != '\0'; ++s)
|
||||
if (*s == c1)
|
||||
*s = c2;
|
||||
}
|
||||
|
||||
char *
|
||||
saveString(s)
|
||||
char *s;
|
||||
{
|
||||
char *result;
|
||||
|
||||
result = (char *)malloc(strlen(s) + 1);
|
||||
strcpy(result, s);
|
||||
return(result);
|
||||
}
|
41
mamelink/griddle/prot.h
Normal file
41
mamelink/griddle/prot.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
|
||||
extern char readc();
|
||||
#define SC 033
|
||||
#define REPLY 0
|
||||
#define STORE 1
|
||||
#define LOW 2
|
||||
#define HIGH 3
|
||||
#define JUMP 4
|
||||
#define LOAD 5
|
||||
#define BADREPLY 6
|
||||
#define CONT 7
|
||||
#define HALTMAIN 8
|
||||
#define HALTALL 9
|
||||
#define HALTCONT 10
|
||||
#define JUMPSUB 11
|
||||
#define RESET 12
|
||||
|
||||
typedef int Boolean;
|
||||
typedef struct
|
||||
{
|
||||
byte portB;
|
||||
byte portA;
|
||||
byte control;
|
||||
byte portC;
|
||||
} Port;
|
||||
|
||||
extern Port *portopen();
|
||||
#define CLOWIN 1
|
||||
#define CLOWOUT 0
|
||||
#define BIN 02
|
||||
#define BOUT 0
|
||||
#define AIN 0x10
|
||||
#define AOUT 0
|
||||
#define CUPOUT 0
|
||||
#define CUPIN 08
|
||||
#define BMODE0 0
|
||||
#define AMODE0 0
|
||||
#define MODESET 0x80
|
||||
|
||||
#define NCARDS 3
|
||||
#define PADDR { 0x70l, 0x60l }
|
BIN
mamelink/griddle/reno.out
Normal file
BIN
mamelink/griddle/reno.out
Normal file
Binary file not shown.
69
mamelink/griddle/util/dumpfstats.c
Normal file
69
mamelink/griddle/util/dumpfstats.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int fredStats[128];
|
||||
|
||||
char *
|
||||
keyName(key)
|
||||
char key;
|
||||
{
|
||||
static char result[10];
|
||||
int i;
|
||||
static struct {
|
||||
char key;
|
||||
char *name;
|
||||
} keyList[] = {
|
||||
' ', "SPACE", '\b', "BACKSPACE",
|
||||
'\t', "TAB", '\n', "LINE FEED",
|
||||
'\r', "RETURN", '\33', "ESC",
|
||||
'\177', "DEL"
|
||||
};
|
||||
|
||||
if ('!' <= key && key <= '~') {
|
||||
sprintf(result, "%c", key);
|
||||
return(result);
|
||||
}
|
||||
for (i=0; keyList[i].key != '\0'; ++i)
|
||||
if (keyList[i].key == key)
|
||||
return(keyList[i].name);
|
||||
if (key < ' ') {
|
||||
sprintf(result, "^%c", key + 0x40);
|
||||
return(result);
|
||||
}
|
||||
sprintf(result, "\\%o", key);
|
||||
return(result);
|
||||
}
|
||||
|
||||
void
|
||||
readFredStats(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
FILE *statFyle;
|
||||
int i;
|
||||
char temp[256];
|
||||
|
||||
if (argc > 1)
|
||||
sprintf(temp, "%s/u0/habitat/fredStats", argv[1]);
|
||||
else
|
||||
strcpy(temp, "/u0/habitat/fredStats");
|
||||
if ((statFyle = fopen(temp, "r")) != NULL) {
|
||||
for (i=0; i<128; ++i)
|
||||
fredStats[i] = getw(statFyle);
|
||||
fclose(statFyle);
|
||||
}
|
||||
if (statFyle == NULL || feof(statFyle)) {
|
||||
for (i=0; i<128; ++i)
|
||||
fredStats[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
|
||||
readFredStats(argc, argv);
|
||||
for (i=0; i<128; ++i)
|
||||
printf("%s -- %d\n", keyName(i), fredStats[i]);
|
||||
}
|
14
mamelink/griddle/util/flushfstats.c
Normal file
14
mamelink/griddle/util/flushfstats.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <stdio.h>
|
||||
|
||||
main()
|
||||
{
|
||||
FILE *statFyle;
|
||||
int i;
|
||||
|
||||
if ((statFyle = fopen("/u0/habitat/fredStats", "w")) != NULL) {
|
||||
for (i=0; i<128; ++i)
|
||||
putw(0, statFyle);
|
||||
fclose(statFyle);
|
||||
} else
|
||||
fprintf(stderr, "couldn't open stat file!\n");
|
||||
}
|
19
mamelink/griddle/util/shorten.c
Normal file
19
mamelink/griddle/util/shorten.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include <stdio.h>
|
||||
|
||||
main()
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while ((c = getchar()) != EOF) {
|
||||
putchar(c);
|
||||
if (c == '\n')
|
||||
i = 0;
|
||||
else if (++i > 78) {
|
||||
putchar('\\');
|
||||
putchar('\n');
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
19
mamelink/griddle/util/trunc.c
Normal file
19
mamelink/griddle/util/trunc.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include <stdio.h>
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int limit;
|
||||
int count;
|
||||
char c;
|
||||
|
||||
limit = atoi(argv[1]);
|
||||
count = 0;
|
||||
while ((c = getchar()) != EOF) {
|
||||
if (count++ < limit || c == '\n')
|
||||
putchar(c);
|
||||
if (c == '\n')
|
||||
count = 0;
|
||||
}
|
||||
}
|
288
render.js
Normal file
288
render.js
Normal file
|
@ -0,0 +1,288 @@
|
|||
|
||||
// C64 RGB values taken from https://www.c64-wiki.com/wiki/Color
|
||||
const c64Colors = [
|
||||
0x000000, 0xffffff, 0x880000, 0xaaffee, 0xcc44cc, 0x00cc55,
|
||||
0x0000aa, 0xeeee77, 0xdd8855, 0x664400, 0xff7777, 0x333333,
|
||||
0x777777, 0xaaff66, 0x0088ff, 0xbbbbbb
|
||||
]
|
||||
|
||||
// from paint.m:447
|
||||
const celPatterns = [
|
||||
[0x00, 0x00, 0x00, 0x00],
|
||||
[0xaa, 0xaa, 0xaa, 0xaa],
|
||||
[0xff, 0xff, 0xff, 0xff],
|
||||
[0xe2, 0xe2, 0xe2, 0xe2],
|
||||
[0x8b, 0xbe, 0x0f, 0xcc],
|
||||
[0xee, 0x00, 0xee, 0x00],
|
||||
[0xf0, 0xf0, 0x0f, 0x0f],
|
||||
[0x22, 0x88, 0x22, 0x88],
|
||||
[0x32, 0x88, 0x23, 0x88],
|
||||
[0x00, 0x28, 0x3b, 0x0c],
|
||||
[0x33, 0xcc, 0x33, 0xcc],
|
||||
[0x08, 0x80, 0x0c, 0x80],
|
||||
[0x3f, 0x3f, 0xf3, 0xf3],
|
||||
[0xaa, 0x3f, 0xaa, 0xf3],
|
||||
[0xaa, 0x00, 0xaa, 0x00],
|
||||
[0x55, 0x55, 0x55, 0x55]
|
||||
]
|
||||
|
||||
const makeCanvas = (w, h) => {
|
||||
const canvas = document.createElement("canvas")
|
||||
canvas.width = w
|
||||
canvas.height = h
|
||||
return canvas
|
||||
}
|
||||
|
||||
const defaultColors = {
|
||||
wildcard: 6,
|
||||
skin: 10,
|
||||
pattern: 15
|
||||
}
|
||||
|
||||
export const canvasFromBitmap = (bitmap, colors = {}) => {
|
||||
if (bitmap.length == 0 || bitmap[0].length == 0) {
|
||||
return null
|
||||
}
|
||||
const { wildcard, pattern, skin } = { ...defaultColors, ...colors }
|
||||
const patternColors = [6, wildcard, 0, skin]
|
||||
const h = bitmap.length
|
||||
const w = bitmap[0].length * 2
|
||||
const canvas = makeCanvas(w, h)
|
||||
const ctx = canvas.getContext("2d")
|
||||
const img = ctx.createImageData(w, h)
|
||||
|
||||
const putpixel = (x, y, r, g, b, a) => {
|
||||
const i = (x * 8) + (y * w * 4)
|
||||
img.data[i] = r
|
||||
img.data[i + 1] = g
|
||||
img.data[i + 2] = b
|
||||
img.data[i + 3] = a
|
||||
img.data[i + 4] = r
|
||||
img.data[i + 5] = g
|
||||
img.data[i + 6] = b
|
||||
img.data[i + 7] = a
|
||||
}
|
||||
|
||||
for (let y = 0; y < bitmap.length; y ++) {
|
||||
const line = bitmap[y]
|
||||
// TODO: What is pattern 255?
|
||||
const patbyte = celPatterns[pattern < 0 || pattern > 15 ? 15 : pattern][y % 4]
|
||||
for (let x = 0; x < line.length; x ++) {
|
||||
const pixel = line[x]
|
||||
let color = null
|
||||
if (pixel == 0) { // transparent
|
||||
putpixel(x, y, 0, 0, 0, 0)
|
||||
} else if (pixel == 1) { // wild
|
||||
const shift = (x % 4) * 2
|
||||
color = patternColors[(patbyte & (0xc0 >> shift)) >> (6 - shift)]
|
||||
} else {
|
||||
color = patternColors[pixel]
|
||||
}
|
||||
if (color != null) {
|
||||
const rgb = c64Colors[color]
|
||||
putpixel(x, y, (rgb & 0xff0000) >> 16, (rgb & 0xff00) >> 8, rgb & 0xff, 0xff)
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.putImageData(img, 0, 0)
|
||||
return canvas
|
||||
}
|
||||
|
||||
export const celsFromMask = (prop, celMask) => {
|
||||
const cels = []
|
||||
for (let icel = 0; icel < 8; icel ++) {
|
||||
const celbit = 0x80 >> icel
|
||||
if ((celMask & celbit) != 0) {
|
||||
cels.push(prop.cels[icel])
|
||||
}
|
||||
}
|
||||
return cels
|
||||
}
|
||||
|
||||
export const frameFromCels = (cels, celColors = null, paintOrder = null) => {
|
||||
if (cels.length == 0) {
|
||||
return null
|
||||
}
|
||||
let minX = Number.POSITIVE_INFINITY
|
||||
let minY = Number.POSITIVE_INFINITY
|
||||
let maxX = Number.NEGATIVE_INFINITY
|
||||
let maxY = Number.NEGATIVE_INFINITY
|
||||
let xRel = 0
|
||||
let yRel = 0
|
||||
let layers = []
|
||||
for (const [icel, cel] of cels.entries()) {
|
||||
if (cel) {
|
||||
const x = cel.xOffset + xRel
|
||||
const y = -(cel.yOffset + yRel)
|
||||
minX = Math.min(minX, x)
|
||||
minY = Math.min(minY, y)
|
||||
maxX = Math.max(maxX, cel.width + x)
|
||||
maxY = Math.max(maxY, cel.height + y)
|
||||
if (cel.bitmap) {
|
||||
const colors = (Array.isArray(celColors) ? celColors[icel] : celColors) ?? {}
|
||||
layers.push({ canvas: canvasFromBitmap(cel.bitmap, colors), x, y })
|
||||
} else {
|
||||
layers.push(null)
|
||||
}
|
||||
xRel += cel.xRel
|
||||
yRel += cel.yRel
|
||||
} else {
|
||||
layers.push(null)
|
||||
}
|
||||
}
|
||||
|
||||
if (paintOrder) {
|
||||
const reordered = []
|
||||
for (const ilayer of paintOrder) {
|
||||
reordered.push(layers[ilayer])
|
||||
}
|
||||
layers = reordered
|
||||
}
|
||||
|
||||
const w = (maxX - minX) * 8
|
||||
const h = maxY - minY
|
||||
|
||||
const canvas = makeCanvas(w, h)
|
||||
const ctx = canvas.getContext("2d")
|
||||
for (const layer of layers) {
|
||||
if (layer && layer.canvas) {
|
||||
ctx.drawImage(layer.canvas, (layer.x - minX) * 8, layer.y - minY)
|
||||
}
|
||||
}
|
||||
return { canvas: canvas, xOffset: minX * 8, yOffset: minY, w: w, h: h }
|
||||
}
|
||||
|
||||
const framesFromAnimation = (animation, frameFromState) => {
|
||||
const frames = []
|
||||
for (let istate = animation.startState; istate <= animation.endState; istate ++) {
|
||||
const frame = frameFromState(istate)
|
||||
if (frame != null) {
|
||||
frames.push(frame)
|
||||
}
|
||||
}
|
||||
return frames
|
||||
}
|
||||
|
||||
export const framesFromPropAnimation = (animation, prop, colors = null) => {
|
||||
const frameFromState = (istate) =>
|
||||
frameFromCels(celsFromMask(prop, prop.celmasks[istate]), colors)
|
||||
return framesFromAnimation(animation, frameFromState)
|
||||
}
|
||||
|
||||
export const framesFromLimbAnimation = (animation, limb, colors = null) => {
|
||||
const frameFromState = (istate) => {
|
||||
const iframe = limb.frames[istate]
|
||||
if (iframe >= 0) {
|
||||
return frameFromCels([limb.cels[iframe]], colors)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return framesFromAnimation(animation, frameFromState)
|
||||
}
|
||||
|
||||
const actionOrientations = {
|
||||
"stand_back": "back",
|
||||
"walk_front": "front",
|
||||
"walk_back": "back",
|
||||
"stand_front": "front",
|
||||
"sit_front": "front"
|
||||
}
|
||||
|
||||
export const framesFromAction = (action, body, limbColors = null) => {
|
||||
const frames = []
|
||||
const chore = body.choreography[body.actions[action]]
|
||||
const animations = []
|
||||
const orientation = actionOrientations[action] ?? "side"
|
||||
const limbOrder = orientation == "front" ? body.frontFacingLimbOrder :
|
||||
orientation == "back" ? body.backFacingLimbOrder :
|
||||
null // side animations are always displayed in standard limb order
|
||||
for (const limb of body.limbs) {
|
||||
if (limb.animations.length > 0) {
|
||||
animations.push({ ...limb.animations[0] })
|
||||
} else {
|
||||
animations.push({ startState: 0, endState: 0 })
|
||||
}
|
||||
}
|
||||
for (const override of chore) {
|
||||
const ilimb = override.limb
|
||||
const newAnim = body.limbs[ilimb].animations[override.animation]
|
||||
animations[ilimb].startState = newAnim.startState
|
||||
animations[ilimb].endState = newAnim.endState
|
||||
}
|
||||
while (true) {
|
||||
const cels = []
|
||||
// const celColors = []
|
||||
let restartedCount = 0
|
||||
for (const [ilimb, limb] of body.limbs.entries()) {
|
||||
const animation = animations[ilimb]
|
||||
if (animation.current == undefined) {
|
||||
animation.current = animation.startState
|
||||
} else {
|
||||
animation.current ++
|
||||
if (animation.current > animation.endState) {
|
||||
animation.current = animation.startState
|
||||
restartedCount ++
|
||||
}
|
||||
}
|
||||
const istate = limb.frames[animation.current]
|
||||
if (istate >= 0) {
|
||||
cels.push(limb.cels[istate])
|
||||
} else {
|
||||
cels.push(null)
|
||||
}
|
||||
// limb.pattern is not a pattern index, it's a LIMB pattern index
|
||||
// celColors.push({ pattern: limb.pattern })
|
||||
}
|
||||
if (restartedCount == animations.length) {
|
||||
break
|
||||
}
|
||||
frames.push(frameFromCels(cels, null, limbOrder))
|
||||
}
|
||||
return frames
|
||||
}
|
||||
|
||||
export const imageFromCanvas = (canvas) => {
|
||||
const img = document.createElement("img")
|
||||
img.src = canvas.toDataURL()
|
||||
img.width = canvas.width * 3
|
||||
img.height = canvas.height * 3
|
||||
img.style.imageRendering = "pixelated"
|
||||
return img
|
||||
}
|
||||
|
||||
export const animate = (frames) => {
|
||||
if (frames.length == 0) {
|
||||
return textNode("")
|
||||
} else if (frames.length == 1) {
|
||||
return imageFromCanvas(frames[0].canvas)
|
||||
}
|
||||
let minX = Number.POSITIVE_INFINITY
|
||||
let minY = Number.POSITIVE_INFINITY
|
||||
let maxX = Number.NEGATIVE_INFINITY
|
||||
let maxY = Number.NEGATIVE_INFINITY
|
||||
for (const frame of frames) {
|
||||
minX = Math.min(minX, frame.xOffset)
|
||||
minY = Math.min(minY, frame.yOffset)
|
||||
maxX = Math.max(maxX, frame.xOffset + frame.w)
|
||||
maxY = Math.max(maxY, frame.yOffset + frame.h)
|
||||
}
|
||||
|
||||
const w = maxX - minX
|
||||
const h = maxY - minY
|
||||
const canvas = makeCanvas(w, h)
|
||||
canvas.style.imageRendering = "pixelated"
|
||||
canvas.style.width = `${w * 3}px`
|
||||
canvas.style.height = `${h * 3}px`
|
||||
let iframe = 0
|
||||
const ctx = canvas.getContext("2d")
|
||||
const nextFrame = () => {
|
||||
const frame = frames[iframe]
|
||||
ctx.clearRect(0, 0, w, h)
|
||||
ctx.drawImage(frame.canvas, frame.xOffset - minX, frame.yOffset - minY)
|
||||
iframe = (iframe + 1) % frames.length
|
||||
}
|
||||
nextFrame()
|
||||
setInterval(nextFrame, 250)
|
||||
return canvas
|
||||
}
|
87
show.js
Normal file
87
show.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
import { animate, celsFromMask, frameFromCels, framesFromAction, framesFromLimbAnimation, framesFromPropAnimation } from "./render.js"
|
||||
|
||||
const readBinary = async (url) => {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
console.log(response)
|
||||
throw Error(`Failed to download ${url}`)
|
||||
}
|
||||
return new DataView(await response.arrayBuffer())
|
||||
}
|
||||
|
||||
export const textNode = (text, type = "span") => {
|
||||
const node = document.createElement(type)
|
||||
node.innerText = text
|
||||
return node
|
||||
}
|
||||
|
||||
export const wrapLink = (element, href) => {
|
||||
const link = document.createElement("a")
|
||||
link.href = href
|
||||
link.appendChild(element)
|
||||
return link
|
||||
}
|
||||
|
||||
export const docBuilder = ({ detailHref, errorContainer }) => {
|
||||
const linkDetail = (element, filename, impl) => {
|
||||
return detailHref ? wrapLink(element, `${detailHref}?f=${filename}`) : element
|
||||
}
|
||||
|
||||
const showError = (e, filename) => {
|
||||
if (errorContainer) {
|
||||
const errNode = document.createElement("p")
|
||||
console.error(e)
|
||||
errNode.appendChild(linkDetail(textNode(filename, "b"), filename))
|
||||
errNode.appendChild(textNode(e.toString(), "p"))
|
||||
if (e.stack) {
|
||||
errNode.appendChild(textNode(e.stack.toString(), "pre"))
|
||||
}
|
||||
errorContainer.appendChild(errNode)
|
||||
}
|
||||
}
|
||||
|
||||
return { linkDetail, showError }
|
||||
}
|
||||
|
||||
export const showAll = (doc, container, filename, values, f) => {
|
||||
for (const value of values) {
|
||||
try {
|
||||
let elements = f(value)
|
||||
if (elements && !Array.isArray(elements)) {
|
||||
elements = [elements]
|
||||
}
|
||||
if (elements) {
|
||||
for (const element of elements) {
|
||||
container.appendChild(doc.linkDetail(element, filename))
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
doc.showError(e, filename)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const propAnimationShower = (prop, colors = {}) =>
|
||||
(animation) => animate(framesFromPropAnimation(animation, prop, colors))
|
||||
|
||||
export const limbAnimationShower = (limb, colors = {}) =>
|
||||
(animation) => animate(framesFromLimbAnimation(animation, limb, colors))
|
||||
|
||||
export const actionShower = (body, limbColors = null) =>
|
||||
(action) => animate(framesFromAction(action, body, limbColors))
|
||||
|
||||
export const celmaskShower = (prop, colors = null) =>
|
||||
(celmask) => animate([frameFromCels(celsFromMask(prop, celmask), colors)])
|
||||
|
||||
export const celShower = (colors = null) =>
|
||||
(cel) => animate([frameFromCels([cel], colors)])
|
||||
|
||||
export const decodeBinary = async (filename, decode) => {
|
||||
try {
|
||||
const value = decode(await readBinary(filename))
|
||||
value.filename = filename
|
||||
return value
|
||||
} catch (e) {
|
||||
return { filename: filename, error: e }
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue