Please login or register.

Login with username, password and session length
Advanced search  


Use of ePSXe before 2.0 is highly discouraged. Mednafen/RetroArch is recommended for playing/testing, pSX is recommended for debugging.

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - lirmont

Pages: [1] 2 3
Tethical / [UTILITY] Win32 Traced (
« on: March 24, 2015, 11:16:09 PM »
Download here: Traced (~500kb).


Usage: trace any PNG image into one or more 3d objects.


Goal: make easily editable 3d map assets similar to FFT.


Traced (Crossbow)

Blender (File -> Import -> Wavefront)


Features by Program Category

  • Optional auto-folding of images based on hue degree of white lines or lines with value = 1 and saturation = 1 (in HSV color space).
  • Image dilation to bleed colors for appropriate 3d displays.

  • Can save file as a 3d object, including scaling.
  • Can save file as a papercraft template, including resizing.

Auto-Folding Example Files (turn on in settings)




If you already have credentials for my other programs, those apply to this program as well. Otherwise, send me a private message if you're willing to help me test this, and I'll send you credentials. Thanks.

Tethical / [MAP] Training Range
« on: March 04, 2015, 11:50:25 AM »
Training Range

View model in browser (~2.5MB).

The target (at various distances away):

I post this target reduction here in case anyone wants to figure out a better looking target (or just something more FFT-style). And, as always, please help me improve this map via suggestions. Thanks.


  • Bigger map.
  • Less dangerous arrangement of targets.

Tethical / FFT-Like Music
« on: September 10, 2014, 09:03:47 AM »
Main composition: Heat of the Moment (1:20).
Background music for this thread: Heat of the Moment (16:24).

So, some of you may be aware that I sunk a month into investigating FFT's music, including being able to replace the waveforms (essentially *.WAV files). I did this because I got to a point in developing the demos for the Kickstarter relaunch where I realized the music just didn't match with the quality of the graphics. A high-quality digital sound, in fact, is not what FFT used. They used pretty low quality (22040Hz) recordings, pumped them through a very heavy (but controllable) reverb, and obviously had very talented musicians write music for that system. While I can't provide the 3rd element, over that month I found free alternatives to the first ~100 of the nearly 200 instruments they used (see: Instruments Wiki), and I began writing code to make use of a software MIDI synthesizer. Sadly, all of this stuff completely lacks the ability to be shown on youtube (some for copyright reasons, mostly for lack of visual nature of music and programming code).

Following the initial investigation, I worked the replacement instruments I found into a replacement table for the purposes of playback and composition. Since I've had the question asked already in-person: "Why does that even matter?" It matters because there are TONS of instruments in the world. If you don't start with just the ones FFT used, it's probably unlikely that you'll use anything like them unless you're skilled at writing music in the style of someone else in the first place. Furthermore, FFT instruments are synthesized, which means you couldn't even hope to find some of them without finding the source material (i.e. reverse-engineering the game) and programming a similar synthesized instrument yourself. So, this is a feature that attempts to offer you a pool of FFT-sounding instruments (without crippling you into only using them) for the purpose of writing songs/music/sound effects that mimic FFT's signature sound (re: low quality audio, massive reverb).

Did you listen to the music I linked yet? As you likely realized, it's all one piece. What changes is the musical theory foundation of: (1) tempo, (2) key (i.e. note like "C"), (3) octave, and (4) scale. These changes have the added benefit of providing an emotional characteristic, like "fear". So, "fear" becomes one configuration for the piece. Meaning, you can ask the engine to play a song like this (i.e. MIDI) in its "fear" configuration. Obviously, you'd have to set this stuff up ahead of time to make sure it sounds good, but the point is that you no longer have to think in terms of music after the initial composition is written; you can think in terms of what it lends itself to emotionally! That's a feature triple-A games have (ex. PSO2), and now so do you -- and it's orchestral-sounding (rather than electronic)!

Thanks for listening and staying interested in Tethical.


Since I don't want to make another post (information is over on twitter anyway), I rewrote gamepad support to use SDL2 (what Steam's Big Picture uses) since someone wrote a Python wrapper for it.

PSX FFT Hacking / Waveform/Instrument Injection
« on: July 04, 2014, 06:35:12 AM »
New instruments in FFT!


Have not decoded the actual definitions for instruments yet. Have managed to replace the wave data (WAVESET.WD) that they operate on.

Involved files:
  • WAVESET.WD (wave data)
  • The ISO it's on.

  • Drag WAVESET.WD into the PSound program.
  • PSound will show 85 waves (0..84).
  • Pick the sound you want to replace.
  • Export the sound (after configuring PSound to not add extra lead out).
  • Document how long the sound is for reference in picking a replacement .WAV file (NOTE: .WAV file should be 22050Hz, 16-bit PCM).
  • Open WAVESET.WD in a hex editor.
  • The first waveform in that file is at 0x0b40; you can identify waves after this point in the file by a sequence of 16 or more consecutive empty bytes; the data streams start as soon as the first non-zero 2-byte set is encountered (like 0x00 0x02 or 0x05 0x02).
  • Jump to the waveform you want to replace.
  • Determine the length to the next set of 16 empty bytes from the start of the data set. This number is the length in bytes of the data streams in the waveform.
  • Use the following program I wrote to encode your wave file like: python WaveFileName.wav LengthInBytes
  • There is now a file containing the data: WaveFileName.wav.bytes
  • In a hex editor that supports paste overwrite (re: the HxD program), paste over the existing data streams back in the WAVESET.WD file.
  • Clear PSound's playlist, and reload the file by dragging it into the playlist area.
  • If you copied the data over correctly, you'll hear the new wave. If not, you'll hear a stock, choppy wave that PSound plays when it can't decode the data (you can just think of it as an error beep).
  • When you're happy with it, you'll need to replace the WAVESET.WD file in the ISO.
  • To do this part manually, open your ISO in a hex editor, and search for the text string: dwdsP (or the hex string 64776473502016CE). This is the start of the WAVESET.WD file in the ISO.
  • Locate the wave you want to replace after that point.
  • Waveforms contain an unbroken line of 2-byte commands that you can see clearly in a standard 16-byte view (re: look for the column of 0x02, 0x06, or 0x03 bytes). Highlight the data stream until you encounter non-file data (i.e. where there would be a two byte command like 0x00 0x02 there is instead a FE FF). Record this value as the initial write for the file.
  • Now, continue highlighting all the way down to just before the next set of consecutive 16 empty bytes (0x03 in the second command byte signals the last stream of the waveform). Copy this data into an ANSI text file (like 0010.txt), removing the spaces between bytes with a replace all tool.
  • Now, re-encode the replacement WAV file against the ISO's data, like: python WaveFileName.wav LengthInBytes TextFileWithBytesFromISO.txt InitialWriteAsNumberOrHexadcimal
  • The content of the resulting .bytes file can be copied over the data stream in the ISO in the same way as the file (paste write).
  • Your ISO now contains a different sound than FFT shipped with.

Usage (for the test in the video on a Japanese ISO of FFT).
Code: (Command Line) [Select]
python C1.wav 6816 C1.txt 0x360
python C2.wav 3808 C2.txt 0xb0
python C3.wav 3936 C3.txt 0x1c0
python C4.wav 1472 C4.txt 0x250
python C5.wav 3104 C5.txt 0x480
NOTE: Requires installing Python and several dependencies: numpy and scipy.

Code: (Python) [Select]
import numpy as np
from itertools import product
from import read

# Pass through values that line up with offsets: 0x0 to 0xf.
acceptedValues = [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, -1.0, -0.875, -0.75, -0.625, -0.5, -0.375, -0.25, -0.125]
acceptedValuesMaxArray = np.array([0.875, -1, ])
allValueRange = np.array(acceptedValues)
# SYNONYMS: 0x06 and 0x03. 0x06 may be some kind of off switch to something 0x02 can do in effects. 0x03 signals the last block follows. They don't do anything special to the data, though.
amplitudeCommands = [0x02, ]
# Cutoff seemed like < 0x5d. Also, cannot use anything evenly divisible by any in range: (0xd, 0xe, 0xf). However, everything above the first 16 (with the exception of the 0x5x block, which is a pass through exactly? the same as 00) are effects, and can safely be ignored for the purposes of writing pre-amplified data into the waveform.
exponents = [i for i in range(0, 0x10) if (i == 0) or ((i % 0xd) > 0) and ((i % 0xe) > 0) and ((i% 0xf) > 0)]
negativePowersOfTwo = list(product(amplitudeCommands, exponents))

# Yield successive n-sized chunks from l. Used to slice bytes of an incoming wave into 28-sample sets (encodes to 14 bytes).
def chunks(l, n):
for i in xrange(0, len(l), n):
yield l[i:i+n]

# Convert sample value (expects 16-bit signed integer) into a value from -1 to 1.
def getSampleValue(n):
thisSampleValue = np.nan_to_num(n) / 32767.0
return thisSampleValue

# Rounds actual data to data represented in the encoding scheme.
def roundToNearestAcceptedValue(sampleValue, valueRange = None):
valueRange = valueRange if valueRange is not None else allValueRange
delta = None
actualNumber = None
for possibility in valueRange:
thisDelta = abs(sampleValue - possibility)
if (delta is None) or (thisDelta < delta):
delta = thisDelta
actualNumber = possibility
return actualNumber

# For values of 0x0 to 0xc in command 0x02, yield: 2**(-n). Values in 0x1x range are a concave falloff. Values in 0x2x range are a convex falloff. Values in 0x3x range are a whole sine wave. Values in 0x4x range are the first 4/5th's of a sine wave.
def getModifier(value):
return 1 / float(2 ** value)

# Get the closest amplitude modifier in the encoding scheme. Intended for use with maximum values.
def getClosestModifier(value, valueRange = acceptedValuesMaxArray, negativePowersOfTwo = negativePowersOfTwo):
# If the value is not zero, go looking for it as a max/min value in the sliding table of values.
if value != 0:
delta = None
actualNumber = None
actualModifier = None
for idx, (command, power) in enumerate(negativePowersOfTwo):
# Typically, get the value of: 1 / 2**power.
modifier = getModifier(power)
# See if any of the maximum values are now equivalent to the supplied value.
for possibility in (valueRange * modifier):
thisDelta = abs(value - possibility)
# If this value is closer than previous values, store it as new solution to best-fit question.
if (delta is None) or (thisDelta < delta):
# Try to escape early. The delta is an exact match.
if thisDelta == 0:
return actualModifier
# Otherwise, store best and continue.
delta = thisDelta
actualNumber = possibility
actualModifier = idx
return actualModifier
# If the value is zero, it can be represented in the pass through, which will be data set (2, 0) at index 0 of negativePowersOfTwo.
return 0

# Translate the 28-sample set into a 16-byte data stream of form: AACC 00112233445566778899AABBCCDD
def getBytesForStream(dataStream):
samples = np.array([getSampleValue(rawValue) for rawValue in dataStream])
maximumValue = samples[abs(samples).argmax()] #max([abs(sample) for sample in samples])
# Store bytes for wave amplitude modifier and stream.
modifierBytes = [0x0, 0x2]
bytes = []
# If the maximum value is not in the default max values list, look it up. Majority case.
modifierIndex = getClosestModifier(maximumValue)
command, power = negativePowersOfTwo[modifierIndex]
thisModifier = getModifier(power)
modifierBytes = [power, command]
scaledDefaultValues = allValueRange * thisModifier
roundedValues = [roundToNearestAcceptedValue(sampleValue, valueRange = scaledDefaultValues) for sampleValue in samples]
# Find indices of values in list.
scaledDefaultValues = list(scaledDefaultValues)
indices = [scaledDefaultValues.index(roundedValue) for roundedValue in roundedValues]
# Get (1, 2), (3, 4), ... (n, n + 1).
groupedIndices = [(indices[i], indices[i+1]) for i in range(0, len(indices), 2)]
# Write the bytes out.
bytes = [] + modifierBytes
for start, finish in groupedIndices:
# Calculate the 2-dimensional array offset in hex of the sliding table values.
x = start * (16 ** 0) + finish * (16 ** 1)
return bytes

# Process all the data of the incoming wave.
def processData(data, samplesPerByte = 2, waveFormBytesPerStream = 14, limit = None):
# Typically: 2 compression modulation bytes followed by compressing 28 bytes into 14 bytes such that 1 byte equals 2 samples. Total: 16 bytes per stream.
fourteenByteDataStreams = chunks(data, waveFormBytesPerStream * samplesPerByte)
# Store return data in string (intended for pasting in a hex editor).
result = ""
totalBytes = 0
# For each stream, bet the bytes.
for dataStream in fourteenByteDataStreams:
theseBytes = getBytesForStream(dataStream)
count = len(theseBytes)
# If this is the last stream to be written, signal with 0x03 instead of 0x02 (or 0x06). Then quit.
if (limit is not None) and (totalBytes + count) >= limit:
theseBytes = theseBytes[0:limit - totalBytes]
theseBytes[1] = 0x03
result += "".join(["%02X" % byte for byte in theseBytes])
totalBytes += len(theseBytes)
# Otherwise, add in form of AACC00112233445566778899AABBCCDD.
result += "".join(["%02X" % byte for byte in theseBytes])
totalBytes += len(theseBytes)
return result

# For arguments, accept: 37 (or) 0x25, 0x800 (or) 2048, etc.
def hexOrInteger(inputString):
return int(inputString)
except ValueError:
return int(inputString, 16)
return 0

# Usage: python WaveFile.wav
# Crossed Streams Usage (short): python WaveFile.wav OtherStream.txt InitialWriteFor
# Crossed Streams Usage: python WaveFile.wav OtherStream.txt InitialWriteFor OtherStreamWriteFor ThisStreamWriteFor
if __name__ == "__main__":
import sys
# Arguments: No input file.
if len(sys.argv) == 1:
print "No input file. Usage: python %s WaveFile.wav\nCross Stream Usage: python %s WaveFile.wav OtherStream.txt InitialWriteFor OtherStreamWriteFor ThisStreamWriteFor\nNOTE: ANSI files only." % (sys.argv[0], sys.argv[0])
# Arguments: No length.
if len(sys.argv) == 2:
# Turn length into an integer.
sys.argv[2] = hexOrInteger(sys.argv[2])
# Arguments: Cross stream file.
if len(sys.argv) == 3:
# Arguments: Cross stream initial write for.
if len(sys.argv) == 4:
# Turn initial write for into integer.
sys.argv[4] = hexOrInteger(sys.argv[4])
# Arguments: Cross into other stream for.
if len(sys.argv) == 5:
# Turn cross into other stream for into integer.
sys.argv[5] = hexOrInteger(sys.argv[5])
# Arguments: Cross back into this stream for.
if len(sys.argv) == 6:
# Turn cross back into this stream for into integer.
sys.argv[6] = hexOrInteger(sys.argv[6])
# Arguments.
thisFilename, waveFilename, length, fileWithStreamFromISO, initialWriteFor, otherStreamWriteFor, thisStreamWriteFor = sys.argv
# Print back the filename for reference.
print waveFilename
# Read data.
rate, data = read(waveFilename)
# Get the bytes of the file body.
result = processData(data, limit = length)
if fileWithStreamFromISO is not None:
crossedStream = ""
parts = []
currentFileCaret = 0
currentResultCaret = 0
resultLength = len(result)
# Read the other stream.
with open(fileWithStreamFromISO, "r") as f:
stream =
# Initial write (write X bytes of the result).
count = initialWriteFor * 2
currentFileCaret += count
currentResultCaret += count
# Enter into a loop of crossing back and forth between the other stream and the result stream.
while currentResultCaret < resultLength:
# Write from other stream.
count = otherStreamWriteFor * 2
currentFileCaret += count
# Write from this stream.
if currentResultCaret < resultLength:
count = thisStreamWriteFor * 2
actualEnd = min(resultLength, currentResultCaret + count)
count = (actualEnd - currentResultCaret)
currentFileCaret += count
currentResultCaret += count
crossedStream = "".join(parts)
# Print the byte count of the combined streams.
print "Bytes:", (len(crossedStream) / 2)
# Write the bytes out to a text file (for copying into a hex editor).
with open("%s.bytes" % waveFilename, "w+") as f:
# Print the byte count of the result.
print "Bytes:", (len(result) / 2)
# Write the bytes out to a text file (for copying into a hex editor).
with open("%s.bytes" % waveFilename, "w+") as f:

PSX FFT Hacking / SMD Parser (WIP)
« on: June 25, 2014, 06:41:21 PM »
I know there's already something that will get a MIDI into SMD format. I was curious to get the notes out of an SMD, though. This is the file "MUSIC_24.SMD" (LvUp L) with varying MIDI instruments: MUSIC_24.mp3.

As soon as I finish cleaning up the code, I'll post a link here. I believe some of the unknowns point to the information the BGM test shows (an actual title, author, and help text), but I wasn't that curious.

Tethical / Tethical Channel Trailer
« on: April 13, 2014, 11:44:07 PM »
Channel Trailer

Switch to high-definition to see how it looked on my screen.



First, I want to thank everybody who's contributed sprites to this website over the years; this video would have been a lot harder without you. In many ways, this is a culmination of my own efforts, too. While, yes, they've been used to super-impose Twitter into an sRPG context, at least that can be done in a straightforward manner now. Earlier in the development of this engine, we were suggesting that you just replace whatever character you want with a special symbol. That means you might have typed "A" for the Twitter logo to show up. Now, you can just type an appropriate Unicode symbol, like the "Bird" (U+1F426; 128038) in "Miscellaneous Symbols and Pictographs" (U+1F300 - U+1F5FF). You can also properly comply with Twitter's somewhat meticulous guidelines for using their logo, too. That would have been a nightmare before when one font took a whole day to make! Now, the Unicode Font Tool can spit out huge fonts with a variety of colors and variants without too much effort from a user.

And the styles available might even turn out really good-looking, too!

And, for that rare occasion where I decided to actually paint on a sprite:

Thanks for watching!

Tethical / Name Entry State, Multi-Language Support
« on: March 05, 2014, 12:41:08 PM »

7 colors. 3 variants. 968,730 embedded images. 2.1 gigs of exported fonts from ~15MB of descriptions + base images (managed by the Font Tool). Also, support for modern Arabic. You literally have no excuse not to support other languages if you can afford or arrange for someone to translate your stuff.

Longer video (~30min): here

Tethical / A Concept-Driven Approach to Lore
« on: February 06, 2014, 07:55:27 AM »
Concept-Driven Lore Quick Look

Please use the larger player to view the video in its intended detail (480p). So, here's a demonstration of how Tethical can help you integrate a backstory (and other art) into something that's a more interactive experience for an end-user. On the backend, the engine reads in a formatted list of sections and entries. Those things have concepts associated with them, and the engine takes care of putting all of that together, meaning you don't have to manually indicate where some phrase should be highlighted. You would just use the phrase in the story, and the engine knows to highlight it (or prepare to highlight it). This feature will be used to help curate the demo (explaining some of the history around this project).

Tethical / Recoloring In-Game (video)
« on: January 20, 2014, 05:36:07 AM »
Recoloring in Action

An early look at recoloring in-game. There are programming-related issues that need to be resolved as to the speed of what this is doing (note: no speed issues on the color replacement in the Sprite Remixer and should be no issues here later). I'll change the output resolution of the game window for future videos to avoid that terrible minification.

Tethical / [UTILITY] Win32 Sprite Remixer (preview)
« on: December 22, 2013, 01:50:52 AM »
As I explained over in the proposal thread, this is a utility that lets you mix and match a lot of the information related to sprites. Everyone will get a chance to play around with it during the relaunch of the Tethical kickstarter, but I wanted to show off some of the features that made it into the program. In this post, I discuss using it as a no-nonsense way to replace colors.


The Base Image (for reference)

This is the standard FFT chocobo sprite (minus the parts I didn't bother to include in the format document, like the portrait).

End Points & Intersections Mode

A color replacement method where the program calculates and exposes where color ramps end and where those color ramps intersect. This mode gives the most control (without forcing you to micromanage all the colors).

End Points Mode

A color replacement mode where just the end points of color ramps are exposed by the program. This essentially lets the user set dark and light values, and the program figures out the middle values.

Intersections Mode

A color replacement mode where only the intersections of color ramps are exposed. This mode lets the user set a minimal number of colors in order to recolor the sprite. It's not suitable for every image, and it relies heavily on perception-corrected hue shifts.

A black chocobo accomplished with 3 reference colors.


Understanding the Underlying Color Technology

When the program loads an image, first it removes all the parts that aren't requested by the user. Then it iterates over the image's pixels, storing unique colors. In other words, if the user is only concerned with the arms of a sprite, the program is only going to consider the colors that the arms use (as opposed to, say, the portrait). That's important, because the program can mix and match other sprites (in effect, remixing them). This color-specific example doesn't do that, but hopefully you get the idea.

From Unique Colors to Color Relationships

Step one is to get all the unique colors in a given part of the image, but just having all the colors in the sub-image isn't enough to simplify anything. Imagine if the program presented you with all 16 unique colors of a sprite. You'd have to set all of them, just as though you were doing it in a graphics editing program. I mean, imagine if the sprite had 160 unique colors or 1600 unique colors. So, to simplify that, the program goes about figuring out how the unique colors are related. Once it's got the colors laid out into color ramps, then we have a lot of interesting information at our disposal. Obviously, it's an easy thought to set out to replace the two colors at the edge of any given color ramp. That's the end points color replacement method.

End Points and the Codominant Pair Color Relationship

If we consider two colors in a pair, how are they related? In the codominant pair, it treats both ends of the color ramp as significant. In other words, we walk directly from the starting color to the ending color over a perceptual color space, and the program lets you set those two colors separately. Because both of the colors are significant, there's no extra information needed to make color choices.

Intersections and the Major-Minor Pair Color Relationship

Where intersections are concerned, if one intersection goes to another intersection, the relationship is a codominant relationship (where the colors at each intersection are significant). If the intersection goes towards an end point, the relationship is a major-minor relationship, where the change in hue and lightness are used in tandem to morph the significant color at each step (creating a new color at each point until you have a replacement for all the insignificant colors contained in the ramp). Effectively, you get a perceptually correct hue shift (based on the original colors).

Filling in the Gaps with Minor-Minor Pair Color Relationships

When two insignificant colors wind up next to each other in a color replacement method, they are put into a minor minor pair. It's exactly like the codominant pair relationship, but it happens after all the other more important pairs are set (and its values are set implicitly by other things in the color map).

Putting it all Together

So, behind the scenes, the program does a lot of complicated color analysis. However, that's exactly where you want the work to be done. Because it does all that analysis, you can set a couple of colors (check out the charcoal chocobo) and get a pretty good result in the intersections mode (with effectively no knowledge of color). You can also get a very controlled result with the "End Points & Intersections" mode. It requires a bit more knowledge of colors, but you can use the suggested color lightness (in association with the color select dialog) to gauge what might be an acceptable color (re: you can pick a color at random and set the lightness to the right range).

Tethical / [MAP] Swelling's Hearth
« on: December 11, 2013, 04:53:07 AM »

Still-frames: 001 and 002.


A map to go with Lijj's awesome Bomb Lord portrait.

Tentatively, the plan for the map in the field test is as follows:
  • The rock holding back the lava flow gets destroyed in the process of a story event.
  • Player's party obtains Drained Organite object.
  • The lava spreads to the circular area.
  • The boss's sprite (not finished yet) appears in the circular lava pit (and cannot leave).
  • The boss begins summoning bomb thralls to attack the player's party.
  • The AI for the bomb thralls attempts to move to a player controlled unit and explode.
  • However, the compression of power required by the explosion takes time. During that time, the player's units can coordinate to knock the time bomb into the area above the circular lava pit. Each successful attack slightly dislodges the ceiling above the circular lava pit.
  • When the player has done this enough times, the game will drop a large rock onto the Bomb Lord, and the Drained Organite will absorb the essence, transforming into Glowing Organite. Light rays will spill in from the empty space above the hole in the ceiling.

Tethical / Passage Card Game Playable Demo/Tutorial
« on: December 04, 2013, 12:06:10 PM »

Play it on the web (~110MB): embedded demo.

Download a desktop edition: versions.


Why, yes, this is made with Tethical's engine. Some of the things Passage happens to share in common with sRPGs in general are: (1) maps (the field), (2) units (the cards), (3) menus (hidden beneath cards), (4) concept of equipping, (5) concept of tactical movement, (6) player phase/enemy phase battle flow, (7) per-unit skills, (8) hp bar, and (9) damage counters.

Anyway, this is the first playable demo I've released, so there will be issues. Kindly report them here, and bear in mind that I've only got a Windows machine to test this stuff on. Though the underlying engine is supposed to properly target Windows, Linux, and Mac, the Mac installer section made a zip file of all things, so I'm concerned.

Thanks in advance for checking this out.

Tethical / There is a Bomb in this thread.
« on: October 21, 2013, 11:52:25 PM »
Bomb in Something Like FFT Cutscene Shader

Side Views: 002 and 003


So, the final thing I wanted to accomplish in some downtime was tackling the render path that FFT: WotL did. This is surely a far cry from that, but I thought you guys might want to see it anyway. This version covers going from the first two shades of the toon shading into the secondary textures (the line art) in the 3rd shade of the toon shader (so it works with any model). It also covers the toon outline. I didn't particularly like what they did with the random shadow texture every couple of video frames, but this does do one (note that the shadow of the bomb has a much larger scale texture) so it can feed in more than one across frames like that (or you can stick with just one). Anyway, it's done in Blender (2.68a), and I sourced a lot of material from the internet to get it to this point. The bomb model, however, is something I made (it's showed up around this forum before, if you care to look).

Tethical / Character Generator Proposal
« on: October 11, 2013, 04:37:25 AM »
So, one of the things that came up in the survey (and I don't know who to credit with the idea because it's anonymous) is the lack of a character generator (re: RPGMaker has a character generator). Now, I'm not partial to the name "Character Generator", and the strictness of the RPGMaker one that comes with the free version I played with is super-restrictive. I'm also not one for making solutions to one-off problems (i.e. making one type of character over and over).

Anyway, my thought was this: what if I write something that describes the sprite formats I already have? In other words, what if I write a program that can tag certain frames (the pieces of the sprite) as arms, legs, heads, etc? And what if it could load a lot of different sprites in that same format and tag those sprites (as male, female, etc)? Then, it could use the sprites as an input, let you pick the parts you want, and output what's known in this community as a "frakensprite". Furthermore, I already have enough code related to colors from the sprite animation program that I could allow those things to be recolored pretty reliably (with very little knowledge of color theory).

This program might become part of the second award tier, followed by the sprite animation tool, followed by the control panel.

Tethical / FE-derived Battle System
« on: October 10, 2013, 02:16:17 AM »

The technique for the 3d map proxy is the same one I used for Mobius' map.

Map tileset: Hyptosis,
Character sprites: Antifarea,


Long story short, one of the suggestions that came up was to have a working demo beforehand (rather than working towards one as a goal). So, here's what will become the basis for a demonstration derived from early Fire Emblem games. It will be the first of four different systems to exist in a combined demo.

Currently, I have the map, the characters, and a story for it. The story and characters will ideally carry over across the four different battle system styles (with teleportation as a central theme to support the drastic change in battle systems).


Layout mockup for battle system.


Early Look

Tethical / Plan for Difficulty and Story "Battles"
« on: October 01, 2013, 11:06:39 PM »
So, quick recap. Kickstarter is going on, and I've been taking the month as downtime to do some of the things that are more game-related than engine-related. This is just the next thing in that process that I wanted to accomplish over that 30-day period.

For a long time now, I've wanted to pursue removing the "kill everything" goal from its prevalence (or its in-vogue use) in story events in these types of games. Now, I have no problem with that goal as it relates strictly to battle; getting out alive may necessitate it; clearing out savage monsters may require it; protecting a target may make it a tempting option (for expediency). My problem comes in when games apply it to non-battle scenarios (i.e. situations without appropriate context).

Now, how can the current system realistically be adjusted to avoid over-dependence on kill-everything tactics? For one, provide the player the opportunity to actually plan their own encounters; this process can go easily between the encounter transition and the formation screen. This process can even inform the formation screen's behavior. Secondly, provide a different set of goals. Lastly, plan for failure.

So, what would such a system be called? Anything related to battle seems to presuppose kill-everything tactics. Calling it any variation of "plan" seemed tedious. I settled on "Rendezvous" (in part because of the word's use in the franchise). Here's the mock-up of what the rendezvous system would look like:

A Flattened Top-Down View of the Map

A Flattened Side-View of the Map

How does difficulty factor into that? If you have a really good tactic, such as someone online finding a sure-fire win for a given scenario, that would effectively defeat the system. As an example of that, imagine if you're given access to a winning tactic to place your ranged units on the high ground at the start of a battle versus a host of short-range melee units. There's probably no real challenge in that.

What can be done about that? For one, limit the player to simple tactics if they choose a simple difficulty. Tactics are broken down by potential company counts; this simulates complexity of maneuvers. Simple tactics require a maximum of one company. This relates directly to practically all battles in FFT. Yes, there may be some distance between the units of a company, but they're all still in the same sphere of influence to begin with, with nothing really differentiating their position. This also doesn't prevent the alternative goals from being pursued.

What happens if you increase the difficulty? You have access to more complex tactics; higher difficulties result in more complicated (and potentially more useful) tactical approaches. This happens at the cost of having to deal with much stronger enemies. AI units can be made to appear to plan to handle whatever general observable company size you have. In other words, if you roamed around with 50+ characters at a time for the past 10 battles and took 3 companies into battle each time, you can expect your enemy will have heard of this and heavily fortified their positions if they knew you were antagonistic to them. Because you aren't required to kill everything to win, this is still a balanced situation. However, you might fail several times (at a cost to unit morale and currency, since you'd probably have to pay non-fanatical units to listen to your orders).

So, what are some of the side effects of this system? Most notably, the planning for failure hopefully keeps unwanted casualties on your side to a bare minimum (something probably important for perfectionists) without forcing you to do so if you don't want to (pick an emergency exit tactic that doesn't care about your unit's lives). Secondly, it can support a system where your choices actually reflect your alignment. In other words, if your character is good, it doesn't have to be good in name or just be "on the side of right" or the unassailable protagonist. If your character is evil, it's also not just in name. Decapitate your enemy's leaders, take prisoners, trick your enemy's soldiers into thinking you're surrendering -- then attack them; you're a bad character, and you ought to be given the opportunity to be that (and suffer the consequences of good units disbanding, having to resort to black markets because no legitimate business will sell you weapons after you get a reputation, etc).

Anyway, that's the plan. The basic tactic would be called "Brute Force" with a company size of 1; higher difficulties would get access to a "Brute Force with Reinforcements" tactic (potentially no company size limit depending how far up the difficulty curve you go). The per-company unit counts expand in that area (if you have 3 companies, you'll pick 3 sizes). Exit strategies offer the ability to trap monsters, take prisoners, plunder captured units, search the map for treasure (limited by skilled units available in unit list), and many other things (like specific limitations for airship and boat combat). Emergency exit strategies are for retreating. Commencing advances to the formation screen state. The map I used for this mock-up is the "Inside of Riovanes Castle" map you can find here:

I have a list of planned tactics, exit strategies, and emergency exit strategies if anyone's interested in seeing those.

Tethical / Camera-Locked Map Proof of Concept
« on: September 27, 2013, 01:37:31 PM »
A short foreword, this is a map created by Mobius for one of his projects. The texture for this map is special because it only exists properly in one view (re: the camera's view).

Front View (3d render at a different size than the source image)

Other views: left, back, right.


UV Map (Texture Coordination)


Anyway, long story short, if your map texture is isometric, it's a trivial process to make a 3d model to act as a proxy over your drawing. This becomes the map, and that map is usable just like any other map (except you should lock the camera's view by ignoring the key presses for rotate map and changing eye level).

This took me about 3 hours to finish, and this was the first time I'd ever tried to do something like this. The core concept is unwrapping the map (automatically) by projecting coordinates from the camera's view. Set up your camera, use the texture as a background image, make the map proxy over it. Unwrap the map. Add a material that uses the texture on the UV map. You're done.

Tethical / Tethical-Jot5 Event Brainstorm
« on: September 18, 2013, 02:00:12 PM »
So, I'm doing the scene from when Dante fights off demons in the intro of the Jot5 patch. Now, if you haven't seen the original, you can watch a version of it here (~6:35):

Here's the new stuff I have to play with:


So, now is your chance to chime in if you want to. Have something cool that could be added in? Mention it here! Practically everything can be changed. For instance, if you think some effect would be more appropriate in dark red, I can do that! Let everybody know in this thread.

Tethical / [EFFECT] Compress
« on: September 17, 2013, 11:33:08 AM »

One of the effects from a Jot5 event (in preparation for a demo event in the Tethical engine at Elric's request). This is simplified from the FFT version because there's something in the actual effect that's not on the sprite sheet (probably geometry, and the lines weren't on the sheet either; also geometry). That covers all the damage-related effects, so I can start putting this event together now. Though I have several other new things that I actually want to do (red-eyed bats flying out of the pit on the map, animated wall torches, Jolting -> Otherworldly -> Terrifying! -> Famicide!! damage-to-text progression).

Tethical / [EFFECT] Stab Up
« on: September 15, 2013, 03:14:28 AM »
Stab Up

One of the effects from a Jot5 event (in preparation for a demo event in the Tethical engine at Elric's request). This is simplified from the FFT version because trying to tackle the amount of particle effects in this particular effect manually will not turn out well. One left to go at this point before I can actually start on the event.

Pages: [1] 2 3