Skip to content

Instantly share code, notes, and snippets.

@jjcf89
Last active December 17, 2021 16:20
Show Gist options
  • Save jjcf89/5b677ef6cd3a9d1ca706cc31f9bcf1cf to your computer and use it in GitHub Desktop.
Save jjcf89/5b677ef6cd3a9d1ca706cc31f9bcf1cf to your computer and use it in GitHub Desktop.
Javascript to draw lines in Yucata's Oracle of Delphi
// Draw paths of each ship through out the game
//
// Need to run code in console and replay the game
// Howto for Chrome:
// * Open finished game https://www.yucata.de/en/Game/Delphi/10373044#page
// * Click on first move in game log
// * Right click on page and select "Inspect"
// * Select the "Sources" tab and in left pane, change Page to Snippets
// * Create "+ New Snippet" and give it a name
// * Copy/paste this code into the snippet
// * Right click on snippet and select Run
// * (Optional) In Oracle window, go to General Settings tab and uncheck "show animations", this will speed up the replay
// * Go back to Oracle window and in the replay tab and press the "Start replay" play button
// * Wait till game has finished running, lines should be getting drawn behind the ships
// * Snippet will stay saved so you can run it again without having to recreate it
//
// Clearing lines:
// * You can clear the lines by running the following javascript in the console or in a different snippet
// ** $(".paths").remove(); $(".warp").remove()
//
// SNAP SVG Cheatsheet: https://gist.github.com/osvik/0185cb4381b35aad3d3e1f5438ca5ca4
if (!y$.game.animateOld) {
y$.game.animateOld = y$.game.animate;
}
y$.game.animate = function(idx, action) {
// Override the animate function so we can draw our lines and skip the other animation effects to save time
var playerNum = y$.utils.getIdx(action.PID);
// Determine color of player
const playerColorIdx = y$.basegame.getColorIdx(playerNum);
const colorPicker = ["red", "green", "blue", "yellow"];
const color = colorPicker[playerColorIdx];
// Offset drawn lines so they don't overlap other ships
const offsetPicker = [
{ x: 0, y: 20 }, // Red: Top left
{ x: 80, y: 10 }, // Green: Top Right
{ x: 0, y: 70 }, // Blue: Bot Left
{ x: 80, y: 80 }, // Yellow: Bot Right
];
const offset = offsetPicker[playerColorIdx];
// Select players ship
const ship = y$.game.snapBoard.select(".boardship" + playerNum);
// The total number of actions since start of game
const moveNum = action.MoveNr;
/* Track round number
* I can't find a round counter so lets make one
*/
// Track the last move number so we can tell if we stopped and restarted
// We have to assume we restarted in the first round...
if (!ship.lastMove || moveNum < ship.lastMove)
{
ship.roundNum = 1;
}
ship.lastMove = moveNum;
/**
* Draws a ships path as the ships move on the board
*/
function addShipPath(startPosition, targetCoord, offX, offY, scale, easing, duration) {
var row = y$.game.Row(targetCoord);
var isEvenRow = row % 2 === 0;
// Get start position
const x1 = startPosition[0];
const y1 = startPosition[1];
// Get end position
const x2 = (y$.game.hexColumnToPixelColumn(y$.game.Column(targetCoord), isEvenRow) + offX);
const y2 = (y$.game.hexRowToPixelRow(row, isEvenRow) + offY);
// Ignore zero length moves
if (x1 != x2 || y1 != y2) {
switch (action.ActionId) {
case y$.game.Actions.PoseidonSelectTargetField:
// ship jumps via Poseidon
console.log(color + ": Warping from " + x1 + "," + y1 + " to " + x2 + "," + y2);
// TODO Not sure if there is some css which would center the text instead of doing it manually
const centerX = -20;
const centerY = 15;
y$.game.snapBoard.text(x1+offset["x"]+centerX, y1+offset["y"]+centerY, "🌌").addClass("warp");
y$.game.snapBoard.text(x2+offset["x"]+centerX, y2+offset["y"]+centerY, "🌌").addClass("warp");
// fall into normal move handling so we draw a line as well
case y$.game.Actions.SelectShipDestination:
// Normal ship movement - Draw line
console.log(color + ": Moving from " + x1 + "," + y1 + " to " + x2 + "," + y2);
line = y$.game.snapBoard.line(x1+offset["x"], y1+offset["y"], x2+offset["x"], y2+offset["y"]).attr({
stroke: color,
}).addClass("paths");
// Workaround: For some reason you can't add this using attr()
line.node.style['marker-end'] = "url(#arrow)"
// Track if we moved
ship.movedThisRound = true;
break;
}
}
// return end position, in pixels
return [x2, y2];
};
// Handle action
switch (action.ActionId) {
case y$.game.Actions.SelectShipDestination:
// Source from real animate function
// for (i = 1; action.ActionEffects.length >= 4 && i < action.ActionEffects[3].length; i++) {
// aSequence.push(y$.game.getAnimateObjectMoveToCoordFunction(y$.game.snapBoard.select('.boardship' + plrIdx), action.ActionEffects[3][i], 24, 39, 1, mina.easeout, 200));
// }
// addAnimationOfOracleResourceCleanup();
// Get start position, this is in pixels
var startPosition = [ship.matrix.e, ship.matrix.f];
for (i = 1; action.ActionEffects.length >= 4 && i < action.ActionEffects[3].length; i++) {
startPosition = addShipPath(startPosition, action.ActionEffects[3][i], 24, 39, 1, mina.easeout, 200);
}
break;
case y$.game.Actions.PoseidonSelectTargetField:
// Source from real animate function
// aSequence.push(y$.game.getAnimateObjectMoveToCoordFunction(y$.game.snapBoard.select('.boardship' + plrIdx), action.ActionParams, 24, 39, 1, mina.linear, 600));
// aSequence.push(y$.game.getAnimateGodStepFunction(plrIdx, y$.game.GOD.POSEIDON, false, y$.game.GODSTEPS.BOTTOM));
// Get start position, this is in pixels
var startPosition = [ship.matrix.e, ship.matrix.f];
addShipPath(startPosition, action.ActionParams, 24, 39, 1, mina.linear, 600);
break;
case y$.game.Actions.finishTurn:
// Write current round to ship position so we can track time
// but only if we've movedThisRound
if (ship.movedThisRound) {
delete ship.movedThisRound;
// TODO Not sure if there is some css which would center the text instead of doing it manually
const moveTextX = -20;
const moveTextY = 15;
y$.game.snapBoard.text(ship.matrix.e+offset["x"]+moveTextX, ship.matrix.f+offset["y"]+moveTextY, ship.roundNum).attr({
stroke: color,
}).addClass("paths");
}
// Next round
ship.roundNum++;
break;
}
// If set to skip animations, exit and resolve promise to skip timeout
if (!y$.userPreferences.getPreference('animated')) {
return $.Deferred().resolve().promise();
} else {
return y$.game.animateOld(idx, action);
}
}
// arrowhead marker definition
marker = `
<marker id="arrow" viewBox="0 0 10 5" refX="10" refY="2.5"
markerWidth="6" markerHeight="6"
orient="auto-start-reverse">
<path d="M 0 0 L 10 2.5 L 0 5 z" />
</marker>`
// Create element case sensitive
markElem = Snap.parse(marker)
$("#arrow").remove()
y$.game.snapBoard.append(markElem)
y$.game.snapBoard.select("#arrow").toDefs()
// Add css, delete the first two rules so if this is run multiple times, we only have one copy of these rules
// Note the first run does delete some unrelated css but at present they aren't used for anything...
/* 1 pixel black shadow to left, top, right and bottom */
/* text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; */
document.styleSheets[0].deleteRule(0);
document.styleSheets[0].deleteRule(1);
document.styleSheets[0].insertRule(".paths { stroke-width: 5px; font-size: 3em; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; }", 0);
document.styleSheets[0].insertRule(".warp { font-size: 2em; }", 0);
@jjcf89
Copy link
Author

jjcf89 commented Oct 12, 2020

Added outline to each number so they are more readable
image

@jjcf89
Copy link
Author

jjcf89 commented Dec 17, 2021

Ran it on a 16 move game for the fun of it. From this post https://www.yucata.de/en/Forum?ForumID=4&postid=138475#138475
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment