This commit is contained in:
David Schmenk 2014-06-02 21:13:21 -07:00
commit d8cc70dbc9
12 changed files with 351 additions and 163 deletions

View File

@ -0,0 +1,66 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.badvision.outlaweditor.ui;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.scene.control.ListCell;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.ComboBoxListCell;
import org.badvision.outlaweditor.data.PropertyHelper;
import org.badvision.outlaweditor.ui.impl.ApplicationUIControllerImpl;
/**
*
* @author blurry
*/
public abstract class EntitySelectorCell<T> extends ComboBoxListCell<T> {
static Map<TextField, Object> lastSelected = new HashMap<>();
TextField nameField;
public EntitySelectorCell(TextField tileNameField) {
super.setPrefWidth(125);
nameField = tileNameField;
}
@Override
public void updateSelected(boolean sel) {
if (sel) {
Object o = lastSelected.get(nameField);
if (o != null && !o.equals(getItem())) {
((ListCell) o).updateSelected(false);
}
textProperty().unbind();
textProperty().bind(nameField.textProperty());
lastSelected.put(nameField, this);
} else {
updateItem(getItem(), false);
}
}
@Override
public void updateItem(T item, boolean empty) {
textProperty().unbind();
super.updateItem(item, empty);
if (item != null && !(item instanceof String)) {
try {
textProperty().bind(PropertyHelper.stringProp(item, "name"));
} catch (NoSuchMethodException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
finishUpdate(item);
} else {
setText(null);
}
}
public void finishUpdate(T item) {
}
}

View File

@ -127,7 +127,7 @@ public abstract class MapEditorTabController {
@FXML
abstract public void scrollMapUp(ActionEvent event);
protected void initalize() {
public void initalize() {
assert mapEditorAnchorPane != null : "fx:id=\"mapEditorAnchorPane\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
assert mapHeightField != null : "fx:id=\"mapHeightField\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
assert mapNameField != null : "fx:id=\"mapNameField\" was not injected: check your FXML file 'mapEditorTab.fxml'.";

View File

@ -85,4 +85,7 @@ public abstract class TileEditorTabController {
abstract public void rebuildTileSelectors();
public void initalize() {
}
}

View File

@ -1,17 +1,9 @@
package org.badvision.outlaweditor.ui.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.Event;
import javafx.scene.control.ListCell;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.ComboBoxListCell;
import javafx.scene.input.DataFormat;
import org.badvision.outlaweditor.Application;
import org.badvision.outlaweditor.Editor;
import static org.badvision.outlaweditor.data.PropertyHelper.*;
import org.badvision.outlaweditor.data.TileUtils;
import org.badvision.outlaweditor.data.TilesetUtils;
import org.badvision.outlaweditor.data.xml.Tile;
@ -34,6 +26,9 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
rebuildTileSelectors();
}
});
tileController.initalize();
mapController.initalize();
imageController.initalize();
}
@Override
@ -127,51 +122,6 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
public static final DataFormat SCRIPT_DATA_FORMAT = new DataFormat("MythosScript");
abstract public static class EntitySelectorCell<T> extends ComboBoxListCell<T> {
static Map<TextField, Object> lastSelected = new HashMap<>();
TextField nameField;
public EntitySelectorCell(TextField tileNameField) {
super.setPrefWidth(125);
nameField = tileNameField;
}
@Override
public void updateSelected(boolean sel) {
if (sel) {
Object o = lastSelected.get(nameField);
if (o != null && !o.equals(getItem())) {
((ListCell) o).updateSelected(false);
}
textProperty().unbind();
textProperty().bind(nameField.textProperty());
lastSelected.put(nameField, this);
} else {
updateItem(getItem(), false);
}
}
@Override
public void updateItem(T item, boolean empty) {
textProperty().unbind();
super.updateItem(item, empty);
if (item != null && !(item instanceof String)) {
try {
textProperty().bind(stringProp(item, "name"));
} catch (NoSuchMethodException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
finishUpdate(item);
} else {
setText(null);
}
}
public void finishUpdate(T item) {
}
};
@Override
public void clearData() {
tileController.setCurrentTile(null);

View File

@ -1,5 +1,6 @@
package org.badvision.outlaweditor.ui.impl;
import org.badvision.outlaweditor.ui.EntitySelectorCell;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
@ -52,7 +53,7 @@ public class ImageEditorTabControllerImpl extends ImageEditorTabController {
imageSelector.setCellFactory(new Callback<ListView<Image>, ListCell<Image>>() {
@Override
public ListCell<Image> call(ListView<Image> param) {
return new ApplicationUIControllerImpl.EntitySelectorCell<Image>(imageNameField) {
return new EntitySelectorCell<Image>(imageNameField) {
@Override
public void finishUpdate(Image item) {
}

View File

@ -1,5 +1,6 @@
package org.badvision.outlaweditor.ui.impl;
import org.badvision.outlaweditor.ui.EntitySelectorCell;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
@ -185,6 +186,7 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
}
}
@Override
public void completeInflightOperations() {
if (getCurrentEditor() != null) {
getCurrentEditor().getCurrentMap().updateBackingMap();
@ -248,7 +250,7 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
}
@Override
protected void initalize() {
public void initalize() {
super.initalize();
mapSelect.setButtonCell(new ComboBoxListCell<org.badvision.outlaweditor.data.xml.Map>() {
{
@ -256,7 +258,7 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
}
@Override
public void updateItem(org.badvision.outlaweditor.data.xml.Map item, boolean empty) {
public void updateItem(Map item, boolean empty) {
textProperty().unbind();
super.updateItem(item, empty);
if (item != null) {
@ -266,13 +268,13 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
}
}
});
mapSelect.setCellFactory(new Callback<ListView<org.badvision.outlaweditor.data.xml.Map>, ListCell<org.badvision.outlaweditor.data.xml.Map>>() {
mapSelect.setCellFactory(new Callback<ListView<Map>, ListCell<Map>>() {
@Override
public ListCell<org.badvision.outlaweditor.data.xml.Map> call(ListView<org.badvision.outlaweditor.data.xml.Map> param) {
return new ApplicationUIControllerImpl.EntitySelectorCell<org.badvision.outlaweditor.data.xml.Map>(mapNameField) {
public ListCell<org.badvision.outlaweditor.data.xml.Map> call(ListView<Map> param) {
return new EntitySelectorCell<Map>(mapNameField) {
@Override
public void finishUpdate(org.badvision.outlaweditor.data.xml.Map item) {
}
public void finishUpdate(Map item) {
}
};
}
});

View File

@ -1,5 +1,6 @@
package org.badvision.outlaweditor.ui.impl;
import org.badvision.outlaweditor.ui.EntitySelectorCell;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -156,7 +157,7 @@ public class TileEditorTabControllerImpl extends TileEditorTabController {
tileSelector.setCellFactory(new Callback<ListView<Tile>, ListCell<Tile>>() {
@Override
public ListCell<Tile> call(ListView<Tile> param) {
return new ApplicationUIControllerImpl.EntitySelectorCell<Tile>(tileNameField) {
return new EntitySelectorCell<Tile>(tileNameField) {
@Override
public void finishUpdate(Tile item) {
setGraphic(new ImageView(TileUtils.getImage(item, Application.currentPlatform)));

View File

@ -5,7 +5,7 @@
<?import javafx.scene.layout.*?>
<?import javafx.scene.web.*?>
<AnchorPane id="AnchorPane" prefHeight="748.0" prefWidth="1024.0" styleClass="mainFxmlClass" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="org.badvision.outlaweditor.MythosScriptEditorController">
<AnchorPane id="AnchorPane" prefHeight="748.0" prefWidth="1024.0" styleClass="mainFxmlClass" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="org.badvision.outlaweditor.ui.MythosScriptEditorController">
<!-- <stylesheets>
<URL value="@/styles/mythosscripteditor.css"/>
</stylesheets>-->

View File

@ -1,19 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="mapsTab" minHeight="0.0" minWidth="0.0" prefHeight="420.0000999999975" prefWidth="677.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.ui.impl.MapEditorTabControllerImpl">
<AnchorPane id="mapsTab" minHeight="0.0" minWidth="0.0" prefHeight="480.0" prefWidth="677.0" stylesheets="@styles/applicationui.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.ui.impl.MapEditorTabControllerImpl">
<children>
<VBox prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ToolBar prefWidth="677.0">
<items>
<Label text="Map:" />
<ComboBox fx:id="mapSelect" minWidth="125.0" onAction="#onMapSelected"/>
<ComboBox fx:id="mapSelect" minWidth="125.0" onAction="#onMapSelected" />
<Button mnemonicParsing="false" onAction="#onMapCreatePressed" text="Create new" />
<Button mnemonicParsing="false" onAction="#onMapClonePressed" text="Clone" />
<Button mnemonicParsing="false" onAction="#onMapExportPressed" text="Export" />
@ -35,35 +33,35 @@
</MenuButton>
</items>
</ToolBar>
<HBox prefHeight="389.0" prefWidth="677.0" VBox.vgrow="ALWAYS">
<HBox prefHeight="438.0" prefWidth="677.0" VBox.vgrow="ALWAYS">
<children>
<AnchorPane prefHeight="200.0" prefWidth="200.0" HBox.hgrow="NEVER">
<children>
<Label text="Name" AnchorPane.leftAnchor="4.0" AnchorPane.topAnchor="14.0" />
<TextField id="mapNameFiled" fx:id="mapNameField" layoutX="53.0" layoutY="11.0" prefWidth="147.0" />
<TextField fx:id="mapWidthField" layoutX="53.0" layoutY="33.0" prefWidth="147.0" />
<Label layoutX="4.0" layoutY="36.0" text="Width" />
<TextField fx:id="mapHeightField" layoutX="53.0" layoutY="55.0" prefWidth="147.0" />
<Label layoutX="4.0" layoutY="58.0" text="Height" />
<CheckBox fx:id="mapWrapAround" contentDisplay="RIGHT" layoutX="4.0" layoutY="77.0" mnemonicParsing="false" text="Wrap at edges" />
<Separator layoutX="4.0" layoutY="101.0" prefWidth="189.0" />
<Label layoutX="4.0" layoutY="108.0" text="Scripts" />
<ScrollPane fitToHeight="true" fitToWidth="true" prefHeight="232.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="157.0">
<TextField fx:id="mapWidthField" layoutX="53.0" layoutY="45.0" prefWidth="147.0" />
<Label layoutX="4.0" layoutY="50.0" prefHeight="16.0" prefWidth="42.0" text="Width" />
<TextField fx:id="mapHeightField" layoutX="53.0" layoutY="79.0" prefWidth="147.0" />
<Label layoutX="4.0" layoutY="84.0" prefHeight="16.0" prefWidth="42.0" text="Height" />
<CheckBox fx:id="mapWrapAround" contentDisplay="RIGHT" layoutX="25.0" layoutY="111.0" mnemonicParsing="false" text="Wrap at edges" />
<Separator layoutX="6.0" layoutY="140.0" prefWidth="189.0" />
<Label layoutX="4.0" layoutY="141.0" text="Scripts" />
<ScrollPane fitToHeight="true" fitToWidth="true" layoutY="171.0" prefHeight="133.0" prefWidth="201.0" AnchorPane.bottomAnchor="114.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="195.0">
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0">
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="95.0" prefWidth="198.0">
<children>
<ListView fx:id="mapScriptsList" editable="true" prefHeight="217.0" prefWidth="199.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<ListView fx:id="mapScriptsList" editable="true" prefHeight="130.0" prefWidth="199.0" AnchorPane.bottomAnchor="-2.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</content>
</ScrollPane>
<ToolBar layoutY="124.0" prefWidth="200.0">
<ToolBar layoutX="1.0" layoutY="157.0" prefWidth="200.0">
<items>
<Button mnemonicParsing="false" onAction="#onMapScriptAddPressed" text="+" />
<Button mnemonicParsing="false" onAction="#onMapScriptDeletePressed" text="-" />
<Button mnemonicParsing="false" onAction="#onMapScriptClonePressed" text="Clone" />
</items>
</ToolBar>
</ToolBar><TextArea fx:id="scriptInfo" editable="false" layoutY="340.0" prefHeight="100.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
</children>
</AnchorPane>
<AnchorPane fx:id="mapEditorAnchorPane" prefHeight="389.0" prefWidth="477.0000999999975" HBox.hgrow="SOMETIMES">
@ -81,4 +79,4 @@
</children>
</VBox>
</children>
</AnchorPane>
</AnchorPane>

View File

@ -40,6 +40,8 @@ class PackPartitions
def debugCompression = false
def javascriptOut = null
def parseMap(map, tiles)
{
// Parse each row of the map
@ -348,11 +350,59 @@ class PackPartitions
}
}
}
/**
* Dump map data to Javascript code, to help in debugging the raycaster. This way,
* the Javascript version can run the same map, and we can compare its results to
* the 6502 results.
*/
def dumpJsMap(rows, texMap)
{
def width = rows[0].size()+2
// Write the map data. First comes the sentinel row.
javascriptOut.println("var map = [")
javascriptOut.print(" [")
(0..<width).each { javascriptOut.print("-1,") }
javascriptOut.println("],")
// Now the real map data
rows.each { row ->
javascriptOut.print(" [-1,")
row.each { tile ->
def b = texMap[tile?.@id]
if ((b & 0x80) == 0)
javascriptOut.format("%2d,", b)
else
javascriptOut.print(" 0,")
}
javascriptOut.println("-1,],")
}
// Finish the map data with another sentinel row
javascriptOut.print(" [")
(0..<width).each { javascriptOut.print("-1,") }
javascriptOut.println("]")
javascriptOut.println("];\n")
// Then write out the sprites
javascriptOut.println("var allSprites = [")
rows.eachWithIndex { row, y ->
row.eachWithIndex { tile, x ->
def b = texMap[tile?.@id]
if ((b & 0x80) != 0) {
// y+1 below to account for initial sentinel row
javascriptOut.format(" {type:%2d, x:%2d.5, y:%2d.5},\n", b & 0x7f, x, y+1)
}
}
}
javascriptOut.println("];\n")
}
def write3DMap(buf, mapName, rows) // [ref BigBlue1_50]
{
def width = rows[0].size()
def height = rows.size()
def width = rows[0].size() + 2 // Sentinel $FF at start and end of each row
def height = rows.size() + 2 // Sentinel rows of $FF's at start and end
// Determine the set of all referenced textures, and assign numbers to them.
def texMap = [:]
@ -389,12 +439,23 @@ class PackPartitions
texList.each { buf.put((byte)it) }
buf.put((byte)0)
// Sentinel row of $FF at start of map
(0..<width).each { buf.put((byte)0xFF) }
// After the header comes the raw data
rows.each { row ->
buf.put((byte)0xFF) // sentinel at start of row
row.each { tile ->
buf.put((byte)texMap[tile?.@id])
}
buf.put((byte)0xFF) // sentinel at end of row
}
// Sentinel row of $FF at end of map
(0..<width).each { buf.put((byte)0xFF) }
if (javascriptOut)
dumpJsMap(rows, texMap)
}
// The renderer wants bits of the two pixels interleaved in a special way.
@ -697,7 +758,7 @@ class PackPartitions
}
}
def pack(xmlPath, binPath)
def pack(xmlPath, binPath, javascriptPath)
{
// Read in code chunks. For now these are hard coded, but I guess they ought to
// be configured in a config file somewhere...?
@ -731,6 +792,10 @@ class PackPartitions
packTexture(image)
}
// If doing Javascript debugging, open that output file too.
if (javascriptPath)
javascriptOut = new File(javascriptPath).newPrintWriter()
// Pack each map This uses the image and tile maps filled earlier.
println "Packing maps."
dataIn.map.each { map ->
@ -746,6 +811,11 @@ class PackPartitions
println "Writing output file."
new File(binPath).withOutputStream { stream -> writePartition(stream) }
// Finish up Javacript if necessary
if (javascriptPath)
javascriptOut.close()
// Lastly, print stats
println "Compression saved $compressionSavings bytes."
if (compressionSavings > 0) {
def endSize = new File(binPath).length()
@ -773,13 +843,14 @@ class PackPartitions
}
// Check the arguments
if (args.size() != 2) {
println "Usage: convert yourOutlawFile.xml DISK.PART.0.bin"
if (args.size() != 2 && args.size() != 3) {
println "Usage: convert yourOutlawFile.xml game.part.0.bin [intcastMap.js]"
println " (where intcastMap.js is to aid in debugging the Javascript raycaster)"
System.exit(1);
}
// Go for it.
new PackPartitions().pack(args[0], args[1])
new PackPartitions().pack(args[0], args[1], args.size() > 2 ? args[2] : null)
}
}

View File

@ -4,57 +4,79 @@ var $ = function(id) { return document.getElementById(id); };
var dc = function(tag) { return document.createElement(tag); };
var map = [
[1,4,3,4,2,3,2,4,3,2,4,3,4],
[1,0,0,1,0,0,0,3,0,0,2,0,3],
[1,1,0,1,1,0,0,1,0,0,3,0,2],
[1,0,0,1,2,3,0,4,0,0,4,0,3],
[1,0,0,0,0,4,0,0,0,0,0,0,4],
[2,0,0,0,0,2,0,0,0,0,0,0,4],
[0,2,2,2,0,0,0,3,0,0,3,0,1],
[3,0,0,2,0,0,0,3,0,0,2,0,3],
[1,0,0,2,0,3,0,2,0,0,4,0,3],
[1,0,0,0,0,2,0,0,0,0,0,0,1],
[3,0,0,0,0,1,0,0,0,0,0,0,3],
[1,0,0,4,0,4,0,3,1,2,4,0,2],
[4,0,0,0,0,0,0,0,0,0,0,0,3],
[1,2,3,3,3,2,2,1,2,4,2,2,2]
[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,],
[ 0, 1, 2, 0, 1, 0, 0, 3, 0, 0, 1, 4, 5, 1, 0, 0, 0,-1,],
[ 4, 0, 0, 7, 0, 2, 1, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0,-1,],
[ 0, 5, 0, 0, 0, 0, 0, 0, 7, 1, 8, 9, 0, 2, 1, 0, 0,-1,],
[ 1, 0, 0, 2, 0,10,11, 0, 2, 0, 0, 8, 0, 7, 1, 0, 0,-1,],
[ 0, 0, 0, 1, 9, 0,12, 0, 0, 0, 4, 5, 0, 0, 0, 3, 0,-1,],
[ 3, 0, 0, 0, 0,12,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,],
[ 0, 4, 5, 2, 0, 0, 0, 0,14,15, 0, 7, 2, 0, 0, 0, 0,-1,],
[ 2, 0, 0, 7, 0, 4, 5, 0, 2,14, 0, 9, 7, 0, 0, 2, 0,-1,],
[ 0, 1, 0, 1, 0,11,10, 0, 8, 0, 0, 4, 0,10,11, 0, 0,-1,],
[ 0, 8, 0, 0, 0,10,11, 0, 9, 0, 0, 5, 0, 0, 0, 0, 0,-1,],
[ 0, 8, 9, 0, 1, 1, 0, 3, 0, 0, 0, 0, 0,10, 0, 0, 0,-1,],
[ 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0,-1,],
[ 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0,-1,],
[ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,-1,],
[ 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,-1,],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,],
[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,]
];
var itemTypes = [
{ img : "sprites/tablechairs.png", block : true }, // 0
{ img : "sprites/armor.png", block : true }, // 1
{ img : "sprites/plantgreen.png", block : true }, // 2
{ img : "sprites/lamp.png", block : false } // 3
{ img : "sprites/lamp.png", block : false }, // 3
{ img : "sprites/lamp.png", block : false }, // 4
{ img : "sprites/lamp.png", block : false }, // 5
{ img : "sprites/lamp.png", block : false } // 6
];
var allSprites = [
// lamp where tree would be
{type:3, x:1.5, y:4.5},
// lamps in center area
{type:3, x:9.5, y:7.5},
{type:3, x:15.5, y:7.5},
// lamps in bottom corridor
{type:3, x:5.5, y:12.5},
{type:3, x:11.5, y:12.5},
{type:3, x:11.5, y:12.5},
// tables in long bottom room
{type:0, x:10.5, y:10.5},
{type:1, x:11.5, y:10.5},
// lamps in long bottom room
{type:3, x:8.5, y:10.5},
{type:3, x:9.5, y:10.5}
{type: 6, x: 1.5, y: 5.5},
{type: 6, x:14.5, y: 1.5},
{type: 6, x: 4.5, y: 4.5},
{type: 6, x: 8.5, y: 5.5},
{type: 6, x:14.5, y: 6.5},
{type: 6, x:15.5, y: 7.5},
{type: 6, x: 9.5, y: 9.5},
{type: 6, x:12.5, y:10.5},
{type: 6, x:14.5, y:10.5},
{type: 6, x: 8.5, y:11.5},
{type: 6, x:10.5, y:11.5},
{type: 6, x:12.5, y:11.5},
{type: 6, x: 6.5, y:12.5},
{type: 6, x: 8.5, y:12.5},
{type: 6, x: 9.5, y:12.5},
{type: 6, x:10.5, y:12.5},
{type: 6, x:11.5, y:12.5},
{type: 6, x: 7.5, y:13.5},
{type: 6, x: 9.5, y:13.5},
{type: 6, x: 6.5, y:14.5},
{type: 6, x:10.5, y:14.5},
{type: 6, x: 8.5, y:15.5},
{type: 6, x:12.5, y:15.5},
{type: 6, x: 1.5, y:16.5},
{type: 6, x: 3.5, y:16.5},
{type: 6, x: 5.5, y:16.5},
{type: 6, x: 6.5, y:16.5},
{type: 6, x: 7.5, y:16.5},
{type: 6, x: 9.5, y:16.5},
{type: 6, x:10.5, y:16.5},
{type: 6, x:11.5, y:16.5},
{type: 6, x:13.5, y:16.5},
{type: 6, x:14.5, y:16.5},
];
// Player attributes [ref BigBlue2_10]
var player = {
x : 1.5, // current x, y position
y : 2.5,
x : 4.2421875, // current x, y position
y : 6.4765625,
dir : 0, // the direction that the player is turning, either -1 for left or 1 for right.
angleNum : 5, // the current angle of rotation
angleNum : 0xA, // the current angle of rotation
speed : 0, // is the playing moving forward (speed = 1) or backwards (speed = -1).
moveSpeed : 0.25, // how far (in map units) does the player move each step/update
rotSpeed : 22.5 * Math.PI / 180, // how much does the player rotate each step/update (in radians)
@ -63,7 +85,7 @@ var player = {
var options = 0;
var debugRay = null; /* Debugging info printed about this ray num, or null for none */
var debugRay = 4; /* Debugging info printed about this ray num, or null for none */
var debugSprite = 0; /* Debugging info printed about this sprite, or null for none */
@ -100,9 +122,6 @@ var wallTextures = [
var userAgent = navigator.userAgent.toLowerCase();
var isGecko = userAgent.indexOf("gecko") != -1 && userAgent.indexOf("safari") == -1;
// enable this to use a single image file containing all wall textures. This performs better in Firefox. Opera likes smaller images.
var useSingleTexture = isGecko;
var screenStrips = [];
var overlay;
@ -413,6 +432,15 @@ function intRenderSprites()
// translate position to viewer space
var dx = sprite.x - player.x;
var dy = sprite.y - player.y;
// Prevent things from overflowing
if (dx > 8 || dy > 8) {
if (sprite.index == debugSprite)
console.log(" too far away (dx=" + dx + ", dy=" + dy + ")");
sprite.visible = false;
sprite.img.style.display = "none";
continue;
}
// Apply rotation to the position
var bSgnDx = (dx < 0) ? -1 : 1;
@ -470,7 +498,7 @@ function intRenderSprites()
var wSpriteTop = 32 - (wSize >> 1);
var wSpriteLeft = wX + wSpriteTop;
if (sprite.index == debugSprite)
console.log(" wX=$" + wordToHex(wX & 0xFFFF) + ", wSpriteTop=$" + wordToHex(wSpriteTop) + ", wSpriteLeft=$" + wordToHex(wSpriteLeft & 0xFFFF));
console.log(" wX=$" + wordToHex(wX) + ", wSpriteTop=$" + wordToHex(wSpriteTop) + ", wSpriteLeft=$" + wordToHex(wSpriteLeft));
var bStartTx = 0;
if (wSpriteLeft < 0) {
if (wSpriteLeft < -wSize) {
@ -579,10 +607,6 @@ function initScreen() {
strip.style.left = 0 + "px";
strip.style.height = "0px";
if (useSingleTexture) {
strip.src = "walls/walls.png";
}
strip.oldStyles = {
left : 0,
top : 0,
@ -728,14 +752,16 @@ function assert(flg, msg) {
}
function byteToHex(d) {
assert(d >= 0 && d <= 255, "byte out of range");
var hex = Number(d).toString(16).toUpperCase();
assert(d >= -127 && d <= 255, "byte out of range");
d = Number(d) & 0xFF;
var hex = d.toString(16).toUpperCase();
return "00".substr(0, 2 - hex.length) + hex;
}
function wordToHex(d) {
assert(d >= 0 && d <= 65535, "word out of range");
var hex = Number(d).toString(16).toUpperCase();
assert(d >= -32767 && d <= 65535, "word out of range");
d = Number(d) & 0xFFFF;
var hex = d.toString(16).toUpperCase();
return "0000".substr(0, 4 - hex.length) + hex;
}
@ -976,6 +1002,10 @@ function intCast(x)
// Perform DDA - digital differential analysis
while (true)
{
// Return immediately if we hit the edge of the map.
if (bMapX < 0 || bMapY < 0 || map[bMapY][bMapX] < 0)
return { wallType: -1, textureX: 0, height: 0, logHeight: 1, xWallHit: 0, yWallHit: 0 }
// Jump to next map square in x-direction, OR in y-direction
if (uless_bb(bSideDistX, bSideDistY)) {
bMapX += bStepX;
@ -1032,7 +1062,9 @@ function intCast(x)
if (x == debugRay) {
console.log("lineHeight=$" + wordToHex(lineHeight) +
", wallType=" + map[bMapY][bMapX] +
", wallX=$" + byteToHex(bWallX));
", wallX=$" + byteToHex(bWallX) +
", wLogHeight=$" + wordToHex(wLogHeight) +
", depth=$" + byteToHex(calcZ(wLogHeight)));
}
// Wrap it all in a nice package. [ref BigBlue2_60]
@ -1058,12 +1090,11 @@ function drawStrip(stripIdx, lineData)
var imgTop = 0;
var styleHeight;
if (useSingleTexture) {
// then adjust the top placement according to which wall texture we need
imgTop = Math.floor(height * (lineData.wallType-1));
var styleHeight = Math.floor(height * numTextures);
if (lineData.wallType < 0) {
var styleSrc = wallTextures[0];
var styleHeight = 0;
} else {
var styleSrc = wallTextures[lineData.wallType-1];
var styleSrc = wallTextures[(lineData.wallType-1) % wallTextures.length];
if (strip.oldStyles.src != styleSrc) {
strip.src = styleSrc;
strip.oldStyles.src = styleSrc

View File

@ -14,6 +14,7 @@ start:
; Conditional assembly flags
DOUBLE_BUFFER = 1 ; whether to double-buffer
DEBUG = 0 ; 1=some logging, 2=lots of logging
DEBUG_COLUMN = 0
; Shared constants, zero page, buffer locations, etc.
!source "render.i"
@ -28,6 +29,15 @@ DEBUG = 0 ; 1=some logging, 2=lots of logging
MAX_SPRITES = 16 ; max # sprites visible at once
NUM_COLS = 63
; Starting position and dir. Eventually this will come from the map
;PLAYER_START_X = $180 ; 1.5
;PLAYER_START_Y = $380 ; 3.5
;PLAYER_START_DIR = 4
PLAYER_START_X = $53E ; special pos for debugging
PLAYER_START_Y = $67A
PLAYER_START_DIR = $A
; Useful constants
W_LOG_256 = $0800
W_LOG_65536 = $1000
@ -405,6 +415,8 @@ castRay: !zone
!if DEBUG >= 2 { jsr .debugFinal }
rts
.hitSprite:
cmp #$FF ; check for special mark at edges of map
beq .hitEdge
; We found a sprite cell on the map. We only want to process this sprite once,
; so check if we've already done it.
and #$40
@ -446,6 +458,16 @@ castRay: !zone
.spriteDone:
jmp .DDA_step ; trace this ray some more
; special case: hit edge of map
.hitEdge:
ldy #0 ; height
lda #1 ; depth
sty txNum ; texture number
jsr saveLink ; allocate a link and save those
lda #0 ; column number
sta txColBuf,x ; save that too
rts ; all done
; wall calculation: X=dir1, Y=dir2, A=dir2step
.wallCalc:
pha ; save step
@ -521,6 +543,7 @@ castRay: !zone
lda #$FF ; clamp large line heights to 255
+ tay ; save the height in Y reg
pla ; get the depth back
!if DEBUG { jsr .debugDepth }
jmp saveLink ; save final column data to link buffer
!if DEBUG >= 2 {
@ -563,6 +586,18 @@ castRay: !zone
+prA
+crout
rts
.debugDepth:
pha
lda screenCol
cmp #4
bne +
+prStr : !text "depth for col4=",0
pla
pha
+prA
+crout
+ pla
rts
}
;------------------------------------------------------------------------------
@ -1087,8 +1122,8 @@ drawSprite: !zone
; (can be used for further manipulation of the values there).
;
saveLink: !zone
sta tmp ; keep height for storing later
sty tmp+1 ; same with depth
sta tmp ; keep depth for storing later
sty tmp+1 ; same with height
ldx screenCol
ldy firstLink,x
bne .chk1
@ -1107,9 +1142,10 @@ saveLink: !zone
lda txNum
sta txNumBuf,x
inc nextLink
!if DEBUG { jsr .debugLink }
rts
.chk1 ; does it need to be inserted before the existing first link?
lda tmp+1
lda tmp
cmp depthBuf,y
bcc .store
; advance to next link
@ -1122,10 +1158,41 @@ saveLink: !zone
sta linkBuf,x
bne .store2 ; always taken; also note: Y contains next link (0 for end of chain)
.chk2 ; do we need to insert before this (non-first) link?
lda tmp+1
lda tmp
cmp depthBuf,y
bcc .insert ; found the right place
bcs .next ; not the right place to insert, look at next link (always taken)
!if DEBUG {
.debugLink:
lda screenCol
cmp #DEBUG_COLUMN
beq +
rts
+ txa
pha
+prStr : !text "Links for col ",0
+prByte screenCol
+prStr : !text ": ",0
ldx screenCol
ldy firstLink,x
.dlup +prStr : !text "[ht=",0
lda heightBuf,y
+prA
+prStr : !text "tx=",0
lda txNumBuf,y
+prA
+prStr : !text "dp=",0
lda depthBuf,y
+prA
+prStr : !text "] ",0
lda linkBuf,y
tay
bne .dlup
+crout
pla
tax
rts
}
; Advance pLine to the next line on the hi-res screen
nextLine: !zone
@ -1161,18 +1228,19 @@ nextLine: !zone
.done: stx pLine+1
rts
; Draw a ray that was traversed by calcRay
; Draw a ray that was traversed by castRay
drawRay: !zone
ldy screenCol
ldx firstLink,y
.lup: lda txNumBuf,x
.lup: lda linkBuf,x ; get link to next stacked data to draw
pha ; save link for later
lda heightBuf,x
beq .skip
sta lineCt
lda txNumBuf,x
sta txNum
lda txColBuf,x
sta txColumn
lda heightBuf,x
sta lineCt
lda linkBuf,x ; get link to next stacked data to draw
pha ; save link for later
; Make a pointer to the selected texture
ldx txNum
dex ; translate tex 1..4 to 0..3
@ -1188,7 +1256,7 @@ drawRay: !zone
+ sta expanderJmp+1 ; set vector offset
!if DEBUG >= 2 { +prStr : !text "Calling expansion code.",0 }
jsr callExpander ; was copied from .callIt to $100 at init time
pla ; retrieve link to next in stack
.skip pla ; retrieve link to next in stack
tax ; put in X for indexing
bne .lup ; if non-zero, we have more to draw
rts ; next link was zero - we're done with this ray
@ -1569,18 +1637,15 @@ expanderJmp:
;-------------------------------------------------------------------------------
; Establish the initial player position and direction [ref BigBlue3_10]
setPlayerPos: !zone
; X=1.5
lda #1
lda #>PLAYER_START_X
sta playerX+1
lda #$80
lda #<PLAYER_START_X
sta playerX
; Y=2.5
lda #2
lda #>PLAYER_START_Y
sta playerY+1
lda #$80
lda #<PLAYER_START_Y
sta playerY
; direction=0
lda #4
lda #PLAYER_START_DIR
sta playerDir
rts