Thursday, March 19, 2020

Exploring Monster Taming Mechanics In Final Fantasy XIII-2: Data Collection

The monster taming aspect of Final Fantasy XIII-2 is surprisingly deep and complex, so much so that I'm interested in exploring it in this miniseries by shoving the monster taming data into a database and viewing and analyzing it with a website made in Ruby on Rails. In the last article, we learned what monster taming is all about and what kind of data we would want in the database, basically roughing out the database design. Before we can populate the database and start building the website around it, we need to get that data into a form that's easy to import, so that's what we'll do today.

Starting a Data Parsing Script

We already identified a good source for most of the data we want to use from the Monster Infusion FAQ post on Gamefaqs.com. However, we don't want to type the thousands of lines of data from this FAQ into our database because we would be introducing human error with the data copying, and the writers of this FAQ have already gone through all of the trouble of entering the data the first time, hopefully without mistakes. Besides, why would we go through such a tedious process when we could have fun writing a script to do the work for us? Come on, we're programmers! Let's write this script.

Since the website will eventually be in Ruby on Rails, we might as well write this script in Ruby, too. It's not absolutely necessary to write the script in Ruby because it's a one-off deal that will only be run once (when it works) to convert the text file into a format that we can easily import into a database, but Ruby is pretty darn good at text processing, so let's stick with it. I like writing scripts in stages, breaking things down into simple problems and starting with an easy first step, so let's do that here. The simplest thing we can do is read in the text file after saving the FAQ to a local file. To add a bit of debug to make sure we have the file read in, let's scan through and print out the section header for the data we're looking for in the file:
File.foreach("ffiii2_monster_taming_faq.txt") do |line|
if line.include? "MLTameV"
puts line
end
end
Already, this code gives the basic structure of what we're trying to do. We're going to read in the file, loop through every line, look for certain patterns, and output what we find that matches those patterns. The real deal will be much more complex, but it's always good to have a working starting point.

This code also has a few problems that we may or may not want to do anything about. First, it's just hanging out in the middle of nowhere. It's not in a class or function or anything more structured. If this was going to be a reusable parsing tool for converting various FAQs into rows of data, I would definitely want to engineer this code more robustly. But hey, this is a one-off script, and it doesn't need all of that extra support to make it reusable. Over engineering is just a waste of time so we'll leave this code out in the open.

Second, I've got two constant strings hard-coded in those lines: the file name and the search string. I may want to stick the search string in a variable because it's not terribly obvious what "MLTameV" means. The file name, on the other hand, doesn't need to be in a variable. I plan to keep this part of the code quite simple, and it's the obvious loop where the file is read in. On top of that, this code will be very specific to handling this exact file, so I want the file name to be tightly coupled to this loop. If the script is ever copied and modified to work on a different file, this file name string can be changed in this one place to point to the new file that that script works with. I don't see a need to complicate this code with a variable.

Third, when this code runs, it prints out two lines instead of one because there's another instance of "MLTameV" in the table of contents of the file. For locating the place to start parsing monster data, we want the second instance of this string. One way to accomplish this task is with the following code:
SECTION_TAG = "MLTameV"
section_tag_found = false

File.foreach("ffiii2_monster_taming_faq.txt") do |line|
if section_tag_found and line.include? SECTION_TAG
puts line
elsif line.include? SECTION_TAG
section_tag_found = true
end
end
Now only the section header line is printed when this script is run. However, as what inevitably happens when we add more code, we've introduced a new problem. It may not be obvious right now, but the path that we're on with the section_tag_found variable is not sustainable. This variable is a piece of state that notifies the code when we've seen a particular pattern in the text file so we can do something different afterward. When parsing a text file using state variables like this one, we'll end up needing a lot of state variables, and it gets unmanageable and unreadable fast. What we are going to need instead, to keep track of what we need to do next, is a state machine.

Parsing Text with a Finite State Machine

Finite state machines (FSM) are great for keeping track of where you are in a process and knowing which state to go to next, like we need to know in the case of finding the section header for the list of tamable monsters in this text file. In the FSM we always have a current state that is one of a finite number of states, hence the name. Depending on the input in that state, the FSM will advance to a next state and possibly perform some output task. Here is what that process looks like in Ruby for finding the second section tag:
SECTION_TAG = "MLTameV"

section_tag_found = lambda do |line|
if line.include? SECTION_TAG
puts line
end
return section_tag_found
end

start = lambda do |line|
if line.include? SECTION_TAG
return section_tag_found
end
return start
end

next_state = start
File.foreach("ffiii2_monster_taming_faq.txt") do |line|
next_state = next_state.(line)
end
First, the states are defined as lambda methods so that they can easily be passed around as variables, but still called as functions. These variables have to be declared before they're used, so the section_tag_found method either has to be defined first because the start method uses it, or all methods could be predefined at the start of the file and then redefined with their method bodies in any desired order. Another way to define these states would be to wrap the whole thing in a class so that the states are class members, but that kind of design would be more warranted if this FSM was part of a larger system. As it is, this parser will be almost entirely made up of this FSM, so we don't need to complicate things.

We can also represent this FSM with a diagram:


The FSM starts in the Start state, obviously, and it transitions to the Section Tag Found state when there's a matching SECTION_TAG. The unlabeled lines pointing back to the same states mean that for any other condition, the state remains unchanged. This diagram is quite simple, but when the FSM gets more complex, it will definitely help understanding to see it drawn out.

Notice that running through the lines of the text file in the foreach loop became super simple. All that's necessary is to feed each line into the next_state, and assign the return value as the new next_state. The current state is kind of hidden because we're assigning the next_state to itself. Also notice that we need to be careful to always return a valid state in each path of each state method, even if it's the same state that we're currently in. Inadvertently returning something that was not a valid state would be bad, as the FSM is going to immediately try to call it on the next line.

Now that we have an FSM started, it'll be easy to add more states and start working our way through the tamable monster data. What do we need to look for next? Well, we can take a look at the data for one monster and see if there are any defining characteristics:
...............................................................................

MONSTER 001

Name---------: Apkallu Minimum Base HP------: 1,877
Role---------: Commando Maximum Base HP------: 2,075
Location-----: Academia 500 AF Minimum Base Strength: 99
Max Level----: 45 Maximum Base Strength: 101
Speed--------: 75 Minimum Base Magic---: 60
Tame Rate----: 10% Maximum Base Magic---: 62
Growth-------: Standard
Immune-------: N/A
Resistant----: N/A
Halved-------: All Ailments
Weak---------: Fire, Lightning
Constellation: Sahagin

Feral Link-----: Abyssal Breath
Description----: Inflicts long-lasting status ailments on target and nearby
opponents.
Type-----------: Magic
Effect---------: 5 Hits, Deprotect, Deshell, Wound
Damage Modifier: 1.8
Charge Time----: 1:48
PS3 Combo------: Square
Xbox 360 Combo-: X

Default Passive: Attack: ATB Charge
Default Skill--: Attack
Default Skill--: Ruin
Default Skill--: Area Sweep
Lv. 05 Skill---: Powerchain
Lv. 12 Passive-: Strength +16%
Lv. 18 Skill---: Slow Chaser
Lv. 21 Skill---: Scourge
Lv. 27 Passive-: Strength +20%
Lv. 35 Passive-: Resist Dispel +10%
Lv. 41 Passive-: Strength +25%
Lv. 42 Passive-: Resist Dispel +44%
Lv. 45 Skill---: Ruinga

Special Notes: Apkallu only spawns twice in Academia 500 AF. If you fail to
acquire its Crystal in both encounters, you will have to close
the Time Gate and replay the area again.

...............................................................................
That series of dots at the beginning looks like a good thing to search for. It repeats at the start of every monster, so it's a good marker for going into a monster state. We'll also want to pass in a data structure that will be used to accumulate all of this monster data that we're going to find. To make it easy to export to a .csv file at the end, we're going to make this data structure an array of hashes, and it looks like this with the new state:
SECTION_TAG = "MLTameV"
MONSTER_SEPARATOR = "........................................"

new_monster = lambda do |line, data|
if line.include? MONSTER_SEPARATOR
return new_monster, data << {}
end
return new_monster, data
end

section_tag_found = lambda do |line, data|
if line.include? SECTION_TAG
return new_monster, data
end
return section_tag_found, data
end

start = lambda do |line, data|
if line.include? SECTION_TAG
return section_tag_found, data
end
return start, data
end

next_state = start
data = []
File.foreach("ffiii2_monster_taming_faq.txt") do |line|
next_state, data = next_state.(line, data)
end

puts data.length
I shortened the MONSTER_SEPARATOR pattern in case there were some separators that were shorter than the first one, but it should still be plenty long to catch all of the instances of separators between monsters in the file. Notice that we now have to pass the data array into and out of each state method so that we can accumulate the monster data in it. Right now it simply appends an empty hash for each monster it finds. We'll add to those hashes in a bit. At the end of the script, I print out the number of monsters found, which we expect to be 164, and it turns out to be a whopping 359! That's because that same separator is used more after the tamable monster section of the file, and we didn't stop at the end of the section. That should be easy enough to fix:
SECTION_TAG = "MLTameV"
MONSTER_SEPARATOR = "........................................"
NEXT_SECTION_TAG = "SpecMon"

end_monsters = lambda do |line, data|
return end_monsters, data
end

new_monster = lambda do |line, data|
if line.include? MONSTER_SEPARATOR
return new_monster, data << {}
elsif line.include? NEXT_SECTION_TAG
return end_monsters, data
end
return new_monster, data
end

# ...
I added another state end_monsters that consumes every line to the end of the file, and we enter that state from the new_monster state if we see the NEXT_SECTION_TAG. Now if we run the script again, we get a count of 166 monsters. Close, but still not right. The problem is that there are a couple extra separator lines used in the tamable monster section, one after the last monster and one extra separator after a sub-heading for DLC monsters. We're going to have to get a bit more creative with how we detect a new monster. If we look back at the example of the first monster, we see that after the separator the next text is MONSTER 001. This title for each monster is consistent for all of the monsters, with MONSTER followed by a three digit number. Even the DLC monsters have this tag with DLC in front of it. This pattern is perfect for matching on a regular expression (regex).

Finding Monster Data with Regular Expressions

A regex is a text pattern defined with special symbols that mean various things like "this character is repeated one or more times" or "any of these characters" or "this character is a digit." This pattern can be used to search a string of text, which is called matching the regex. In Ruby a regex pattern is denoted by wrapping it in forward slashes (/), and we can easily define a regex for our MONSTER 001 pattern:
SECTION_TAG = "MLTameV"
MONSTER_SEPARATOR = "........................................"
NEXT_SECTION_TAG = "SpecMon"
NEW_MONSTER_REGEX = /MONSTER\s\d{3}/

find_separator = nil

end_monsters = lambda do |line, data|
return end_monsters, data
end

new_monster = lambda do |line, data|
if NEW_MONSTER_REGEX =~ line
return find_separator, data << {}
elsif line.include? NEXT_SECTION_TAG
return end_monsters, data
end
return new_monster, data
end

find_separator = lambda do |line, data|
if line.include? MONSTER_SEPARATOR
return new_monster, data
end
return find_separator, data
end

# ...
The NEW_MONSTER_REGEX is defined as the characters MONSTER, followed by a space (\s), followed by three digits (\d). I changed the new_monster state to look for a match on our new regex, and added a find_separator state to still search for the MONSTER_SEPARATOR. Notice that the FSM will bounce between these two states, so the state that's defined later has to be declared at the top of the file, otherwise Ruby will complain that find_separator is undefined in new_monster.

These regex patterns are useful and powerful, but they can also be quite tricky to get right, especially when they get long and complicated. We'll be using them to pull out all of the data we want from each monster, but we'll try to keep them as simple as possible. The next regex is more complicated, but it will allow us to pull nearly all of the properties for each monster and put it into the empty hash that was added to the list of hashes for that monster. Ready? Here it is:
MONSTER_PROP_REGEX = /(\w[\w\s\.]*\w)-*:\s(\S+(?:\s\S+)*)/
We'll break this regex apart and figure out what each piece means separately.

The first part of the regex, (\w[\w\s\.]*\w), is surrounded by parentheses and is called a capture. A capture will match on whatever the pattern is inside the parentheses and save that matching text so that it can be accessed later. We'll see how that works in the code a little later, but right now we just need to know that this is how we're going to separate out the property name and its value from the full matching text. This particular capture is the property name, and it starts with a letter or number, symbolized with \w. The stuff in the brackets means that the next character can be a letter or number, a space, or a period. Any of those characters will match. Then the following '*' means that a string of zero or more of the preceding character will match. Finally, the property name must end with a letter or number, symbolized with \w again. The reason this pattern can't just be a string of letters and numbers is because some of the property names are multiple words, and the "Lv. 05 Skill" type properties also have periods in them. We want to match on all of those possibilities.

The next part of the regex is -*:\s, which simply means it will match on zero or more '-', followed by a ':', followed by a space. Reviewing the different lines for the MONSTER 001 example above, we can see that this pattern is indeed what happens. Some cases have multiple dashes after the property name, while others are immediately followed by a colon. The colon is always immediately followed by a single space, so this should work well as our name-value separator. It's also outside of any parentheses because we don't want to save it for later.

The last part of the regex is another capture for the property value: (\S+(?:\s\S+)*). The \S+—note the capital S—will match on one or more characters that are not white space. It's the inverse of \s. The next thing in this regex looks like yet another capture, but it has this special '?:' after the open parenthesis. This special pattern is called a grouping. It allows us to put a repeat pattern after the grouping, like the '*' in this case, so that it will match on zero or more of the entire grouping. It will not save it for later, though. Since this grouping is a space followed by one or more non-space characters, this pattern will match on zero or more words, including special characters. If we look at the example monster above, we see that this pattern is exactly what we want for most of the property values. Special characters are strewn throughout, and it would be too much trouble to enumerate them all without risking missing some so we cover our bases this way.

Fairly simple, really. We're going to match on a property name made up of one or more words, followed by a dash-colon separator, and ending with a property value made up of one or more words potentially including a mess of special characters. Note how we couldn't have used the \S character for the property name because it would have also matched on and consumed the dash-colon separator. We also could not have used the [\s\S]* style pattern for the words in the property value because it would have matched on any number of spaces between words. That wouldn't work for the first few lines of the monster properties because there are two name-value pairs on those lines. Now that we have our regex, how do we use those captured names and values, and how exactly is this going to work for the lines with two pairs of properties on them? Here's what the new add_property state looks like with some additional context:
# ...

MONSTER_PROP_REGEX = /(\w[\w\s\.]*\w)-*:\s(\S+(?:\s\S+)*)/

find_separator = nil
new_monster = nil

end_monsters = lambda do |line, data|
return end_monsters, data
end

add_property = lambda do |line, data|
props = line.scan(MONSTER_PROP_REGEX)
props.each { |prop| data.last[prop[0]] = prop[1] }
return new_monster, data if line.include? MONSTER_SEPARATOR
return add_property, data
end

new_monster = lambda do |line, data|
if NEW_MONSTER_REGEX =~ line
return add_property, data << {}
elsif line.include? NEXT_SECTION_TAG
return end_monsters, data
end
return new_monster, data
end

# ...
The double-property lines are handled with a different type of regex matcher, line.scan(MONSTER_PROP_REGEX). This scan returns an array of all of the substrings that matched the given regex in the string that it was called on. Conveniently, if the regex contains captures, the array elements are themselves arrays of each of the captures. For example, the scan of the first property line of our MONSTER 001 results in this array:
[['Name', 'Apkallu'],['Minimum Base HP', '1,877']]
We can simply loop through this array, adding property name and property value to the last hash in the list of hashes. Then, if the line was actually the MONSTER_SEPARATOR string, it didn't match any properties and we'll move on to the next monster. Otherwise, we stay in the add_property state for the next line.

One last thing that we're not handling is those multi-line descriptions and special notes. We need to append those lines to the correct property when we come across them, but how do we do that? Keep in mind that these extra lines won't match on MONSTER_PROP_REGEX, so we can simply detect that non-match, make sure it's not an empty line, and add it to the special notes if it exists or the description if the special notes doesn't exist. Here's what that code looks like in add_property.
MONSTER_PROP_EXT_REGEX = /\S+(?:\s\S+)*/

# ...

add_property = lambda do |line, data|
props = line.scan(MONSTER_PROP_REGEX)
props.each { |prop| data.last[prop[0]] = prop[1] }
return new_monster, data if line.include? MONSTER_SEPARATOR

ext_line_match = MONSTER_PROP_EXT_REGEX.match(line)
if props.empty? and ext_line_match
if data.last.key? 'Special Notes'
data.last['Special Notes'] += ' ' + ext_line_match[0]
else
data.last['Description'] += ' ' + ext_line_match[0]
end
end

return add_property, data
end
By putting the extra code after the return if the line is the MONSTER_SEPARATOR, we can assume that this line is not the MONSTER_SEPARATOR and just check if the MONSTER_PROP_REGEX didn't match and there's something on the line. Then decide on which property to add the line to, and we're good to go.

Okay, that was a lot of stuff, so let's review. First, we read in the file that we wanted to parse that contains most of the monster taming data we need. Then, we loop through the lines of the file, feeding them into a FSM in order to find the section of the file where the list of monsters is and separate each monster's properties into its own group. Finally, we use a few simple regex patterns to capture each monster's property name-value pairs and add them to a list of hashes that will be fairly easy to print out to a .csv file later. All of this was done in 66 lines of Ruby code! Here's the program in full so we can see how it all fits together:
SECTION_TAG = "MLTameV"
MONSTER_SEPARATOR = "........................................"
NEXT_SECTION_TAG = "SpecMon"
NEW_MONSTER_REGEX = /MONSTER\s\d{3}/
MONSTER_PROP_REGEX = /(\w[\w\s\.]*\w)-*:\s(\S+(?:\s\S+)*)/
MONSTER_PROP_EXT_REGEX = /\S+(?:\s\S+)*/

find_separator = nil
new_monster = nil

end_monsters = lambda do |line, data|
return end_monsters, data
end

add_property = lambda do |line, data|
props = line.scan(MONSTER_PROP_REGEX)
props.each { |prop| data.last[prop[0]] = prop[1] }
return new_monster, data if line.include? MONSTER_SEPARATOR

ext_line_match = MONSTER_PROP_EXT_REGEX.match(line)
if props.empty? and ext_line_match
if data.last.key? 'Special Notes'
data.last['Special Notes'] += ' ' + ext_line_match[0]
else
data.last['Description'] += ' ' + ext_line_match[0]
end
end

return add_property, data
end

new_monster = lambda do |line, data|
if NEW_MONSTER_REGEX =~ line
return add_property, data << {}
elsif line.include? NEXT_SECTION_TAG
return end_monsters, data
end
return new_monster, data
end

find_separator = lambda do |line, data|
if line.include? MONSTER_SEPARATOR
return new_monster, data
end
return find_separator, data
end

section_tag_found = lambda do |line, data|
if line.include? SECTION_TAG
return find_separator, data
end
return section_tag_found, data
end

start = lambda do |line, data|
if line.include? SECTION_TAG
return section_tag_found, data
end
return start, data
end

next_state = start
data = []
File.foreach("ffiii2_monster_taming_faq.txt") do |line|
next_state, data = next_state.(line, data)
end
And here's the corresponding FSM diagram:

Final FSM diagram of tamable monster parser

We still need to write the collected data out to a .csv file so that we can import it into a database, but that is a task for next time. Also, notice that we have done almost no data integrity checks on this input other than what the FSM and regex patterns inherently provide. Any mistakes, typos, or unexpected text in the file will likely result in missing or corrupt data, so we'll need to do some checks on the data as well. Additionally, this data is just the tamable monster data. We still need the other table data for abilities, game areas, monster materials, and monster characteristics. However, this is a great start on the data that was the most difficult to get, and we ended up with quite a few extra properties that we weren't intending to collect in the list. That's okay, I'm sure we'll find a use for them.

Monday, March 16, 2020

Building Cities!

What's going on everyone!?


Today for the #2019gameaday challenge I played a solo game of Carcassonne on the mobile app with 2 AI and actually won!

It was a good game and very close until the ene but some wisely placed farmers ended up winning me the game!

As one of my favorite games I don't think I'll ever get sick of this one!

As always, thank you for reading and don't forget to stop and smell the meeples! :)

-Tim

Friday, March 6, 2020

Ween : The Prophecy - Alternative Paths And Final Rating

Written by Alfred n the Fettuc

Before submitting WEEN to the PISSED rating, we need to study the alternative paths that you can take through the game. I counted two (but I might also have missed something), one using the fish amulet to breathe underwater, and the other attainable by choosing the second door when you exit the temple, just before the ant garden.

The first hint about an alternative path comes from our friend URM

First alternative path : Sea monsters eating each others.

Restarting the game, I scan once more every screen to see what I could have missed but don't find anything before the lake itself (I still don't know if I can do anything with the bolt I found on OHKRAM's balcony by the way). Turns out that on the first venom/pollen puzzle, there is a very tiny leave hidden in the corner of the screen.

Obvious isn't it?

Considering all the pixel-hunting I had to do in order to progress later in the game, I'm really surprised I didn't spot the leaves on my first play-through. I think at this point of the game, I didn't really need to search every nook and cranny of every place I went. Anyway, I make the monster appear on the bridge, get the feather, use it to make the venom and pollen appear in the chest, and mix a potion of growth out of the two reagents. And what do you know…

More strawberries!!!

I call URM and give him the strawberries. Joyful, he drops a small ingot of gold that fits perfectly with the half-statue to make a complete fish amulet. Guess it means that URM had the amulet since the very beginning and just didn't give it to me because I didn't have enough strawberries in my pocket… stupid greedy bat. Using the amulet on the water allows me to enter it and breathe underwater. URM comes back afterwards and get back the Elixir from me, so the hint of an alternative path works whatever path you choose. Nice touch.

Do fishermen dream of electric fish?

Just before arriving on this screen, I witness a little cutscene with a big barracuda-like fish eating some kind of metal pole. When I click on the seaweeds on the left of the screen, a little fish appears and get eaten by the same barracuda-like fish, that WEEN describes as a wurk, a greedy fish that could eat anything. I'm starting to suspect that we'll have to make him eat the electric fish one way or another. Clicking on the staircase sets a trap where iron bars appear from the wall to stop me from going up. Messing with the electric fish gets me zapped. I spend some time looking around until a little bug appears… it's our friend the useless mosquito sent by KRAAL!

Hey there little buddy, I thought I would only kick your ass much later in the game…

I catch it pretty easily and feed it to the electric fish… Just when I was wondering if it meant that taking this alternative path would make the mosquito disappear from the rest of the game, another one quietly arrives and lands at the exact same place. I'm guessing KRAAL has an infinite army of mosquitos underlings for some reason. Knowing that the electric fish seems to love mosquitos, I get the other insect and drop it near the hole where the wurk is hidden. It exits and eats the fish, resulting in death by electrocution. I grab the glass piece on the ground and cuts the wurk open.

Gross

I use the steel bar found into the belly of the beast in the small hole near the door, making it bigger. Clicking on the hole now makes another marine monstrosity appear as a moray eel tries to catch me. Messing with the seaweeds on the left make another innocent fish wander around and gets eaten by the moray eel.

Underwater massacre

Inside the fish I find a harpoon point (what do they eat in that lake?) that I combine with my metal bar to make a perfectly fine harpoon. Trying to use it in the moray eel hiding place doesn't work though. Looking in the seaweed to find another fish, I catch it with my harpoon before it gets eaten and then feed it to the moray eel, hoping it would choke on my harpoon, but no. It just eats the fish and spits back my harpoon. What a nice monstrosity. Pixel-hunting the place once more, I discover a crack on the side of the barred staircase. Destroying a part of the wall with my harpoon, and trying to climb the staircase once again breaks the trap. However, the iron bars are now stuck in the stone.

Not for the marine life around here, that's for sure.

Using my trusty harpoon, I catch another fish from the seaweed and put it between the iron bars. It works! The moray eel catch the harpoon point and forces the iron bars open with its voracity. Now that's what I call one hungry fish! Finally, I'm able to exit this horrible place and get to the entrance of the dragon temple with the wasp trap and the snake.

So all in all, this path allows me to avoid the goblin-looking statue with its sword and the Orivor puzzle. I kinda prefer the underwater path as I think the puzzles are more fun. However, I'll probably never go in a lake again in my life now that I've seen what's in it…

Second alternative path : Laser-eye petrifying dinosaurs

After getting the three grains of sand and exiting the temple (and before the two dimwits lost my haversack), I was presented with two doors. The door on the right, that I chose, brought me to the ant garden puzzle where I had to mix a digitalis meal for the ant queen. Selecting the door on the left brings me to another garden, where some kind of huge laser-eyes dinosaur petrifies URM the second we get in!

We hold the winner in the Coktel Vision teeth contest

PETROY appears and tells me that KOR, the deity that's pictured on the left, can help URM, but I need to give him offerings. Namingly, the power of thunder, the star of light and the wealth of the tide… Just that. I grab what appears to be a net (probably in order to get the wealth of the tide. I knew I should have brought another dead fish from the underwater segment). Trying to operate the well tells me that I need a handle to work the pulley. The right of the screen allows me to exit to another part of the garden.

A grill? Maybe I'll be able to barbecue the wealth of the tide…

Getting the grill allows a huge orange crab to exit the trap. I grab a fish from the river with my net. Clicking a second time on the river makes the fairy of the river appear! She tells me that in her river lives a crab with sharp pincers (doh!), and that great riches can be found in the water. Trying to use the grill as a sieve doesn't work though. Not finding anything else, I go back to the statue of KOR in order to offer him the fish I just caught. No reaction. So I guess the wealth of the tide refers to actual wealth. Pixel-hunting the first screen, I find that I can remove the hoop from the barrel.

You know? For kids!

Using the grill in the hoop, I make an actual sieve. Using it on the river allows me to get a few gold nuggets. Going back to the statue, I can put the nuggets at the feet of the statue but nothing happens. I guess he wants the three elements before doing anything. I realize I still have a fish in my inventory and go back to the river. Putting the fish in the trap next to it makes the big orange crab come back in order to devour this meal. I catch the crab (with my bare hands… WEEN is clearly braver than me). Not finding anything to do with it, I try using my other inventory items everywhere. Putting the sword in the hand of the statue, it attracts lightning! After hitting the sword, the lightning falls on the ground and I can grab it in my hands.

Pretty sure that's not how lightning works.

Trying to put the lightning on the pedestal to offer KOR the "power of thunder", WEEN tells me that he's got far better things to do with this object for the moment… So first, thank you, protagonist, for this hint but could you please do as you're told? Secondly, ok, what else can I do with a solidified lightning? Use it as a handle for the well of course! I pull up something that looks like a chest from the bottom of the well and I can put the lightning on the pedestal afterwards. Thank you, WEEN! The chest is locked by a heavy metal chain that I use my crab to cut. It still doesn't open, though, so I get my sword back and use it as a lever to open the chest (swords used as levers during the game : 4). Inside the chest is a key that I use to open the lock under the beast statue. In it I find a sun effigy, which is sure to be "the star of light". I put it on the pedestal and KOR reanimates URM, who doesn't take long to be his normal self again!

Ungrateful fruit-eating bastard

And then I arrive at the garden with the view on Volcano Island, the worm and the giant mushrooms. I tend to prefer this path also to the one with the ant queen, if only because I spent way too much time on the ant queen screen turning my copper ball into a pipe and a cauldron and vice-versa…


FINAL RATING

Finally, the moment we've all been waiting for. I tend to be a bit afraid of the PISSED rating because I know this game is fondly remembered by many, but I'll try my best to give it a fair trial.

Puzzles and Solvability

The puzzles are pretty fun overall. The game is a nice suite of inventory-based puzzles and there are a lot of them. However, the game is a bit on the easy side and a few of the puzzles are repetitive without enough differences between them. The room with the fireflies comes to mind where you're supposed to repeat the same tedious steps five times. The other problem is that you stumble a bit too often on the solution instead of wanting to do something and successfully do it. That's usually the issue with games with a single "action" button (as opposed to a list of verbs or a parser), in my humble opinion, but in this kind of games where things happen because "magic", I think that clicking on random things and see what happens is a big part of the fun, like a less chaotic version of Gobliins 2.

When the game avoids being too easy, however, it tends to fall pretty quickly in the "obscure" territory. The dragon battle, for example comes to mind, or the potion mixing.

Never forget the mighty battle of the cat and the beagle.

Thorough pixel-hunting is a huge part of the game as well and it can be infuriating at times, especially when you think you have the good solution and can't make it work. Globally, the game could do with a little more hints, even subtle ones. Too often was I stumbling in the dark just trying to make something happen with no clear objective of my goal.

Having two branching paths (even if it's for a short period of time) is great though, and adds replayability, which is still rare enough in adventure games to be underlined.

Final Score : 6. Overall, the puzzle design is solid, pleasant and there are a lot of things to do. A few roadblocks are difficult enough without being unsolvable. The fact that you are too often stumbling in the dark is what prevents it to get a 7, but just quite.

Interface and Inventory

As was noted by Ilmari in his playthrough of Gobliins 2, the interface shares some similarities, which is a novelty for a Coktel Vision game. It's probably because it works. You can combine inventory items, use items on yourself, etc. I think the guys at Coktel were working on something that would be used in all of their games at the time if only because they left the "fast movement" icon in the menu without using it once in the game. It was Coktel's take on something similar to the SCUMM engine, even if not as brilliant.

There is even a notepad to keep track of whatever seems important (like potion recipes)

The interface is overall pretty functional, but it has a few flaws that really get irritating in the long run. I've rambled enough on the transformations of the copper ball/sword/pipe/cauldron. It's because you do that ALL THE TIME. And what is a charming little animation in the beginning of the game are excruciating when you do that fifteen times in a row because you're trying to solve a puzzle and don't know which tool to use. The fact that you have to go through the copper ball transformation every time you want to change the sword into a cauldron is more irritating than it has any right to be.

There are other issues as well. Using the glue on the firefly works but not the other way around. Granted, it makes more sense in this order but when you're trying to find the solution to an obscure puzzle, you don't necessarily try the two sides of an item interaction. There is also a little "slugginess" to the whole game (like a few milliseconds too long) that makes the whole thing a little too slow for my taste. But it might also be the emulator I used so I won't take it into account.

The integrated joker system is a nice touch. In a time before the internet, it was always a solution to make some progress in the game if you're completely stuck. I tried it here and there after my playthrough, though, and it could beneficiate from a little subtlety by guiding you on the right path instead of telling the solutions outright. But still, it's always better than throwing the game disks against a wall in frustration.

Final Score : 4. Functional, but a few issues tarnish the whole experience here and there.

Story and Setting

Well… this one is tricky. I'm pretty sure the story as a whole made some kind of sense to someone at Coktel Vision (or they were under a lot of drugs), but after having completed the game, I still have little clues about exactly who is OPALE, what the REVUSS is, what the BORGOL is, why the two stupid twins change their height every five seconds, etc… The whole story comes out as quite a mess, and it's not a translation issue as I've tried the french version and it's more or less the same thing.

I still want someone to explain to me why my haversack was an owl the whole time…

Then again, the whole "it's magic" works with this universe and the sense of mystery permeates everything, but that's something that enters in another category. As a story in and by itself, it doesn't make a lot of sense. I'd also love to have some kind of confrontation with KRAAL at the end instead of an over-complicated Bond villain scheme to foil. It's like if at the end of Legend of Kyrandia, you just had to disarm a trap instead of confronting Malcolm while you've spent the whole game chasing him.

The same can be said about the places you're exploring. Once you exit the cave complex from underneath OHKRAM's house, you spend your time going in and out of caves and gardens with little coherence. It's not a big deal in itself, as most of the puzzles are self-contained to one screen, but it doesn't make you feel like you're making any progress, more like you're being lugged around random places.

Final score : 3. The story is serviceable, nothing else. You solve puzzles and sometimes, someone talks to you spouting nonsense.

Sound and Graphics

In the visual department, the game suffers from a strange dichotomy. The places you explore are mostly pretty and nicely detailed. The catacombs and temples are creepy enough and the whole "sunsets and moonlight" ambiance suits the magical atmosphere overall. However, I found the monster and creature design to be quite hideous, to be honest. The dragon, the orivors, the mosquitos… I guess a monster is supposed to be ugly, and it's also a matter of taste, but I frankly disliked the overall creature design.

The horror… the horror…

And then there are digitized actors in Halloween masks integrated in all this. If you remove UBI and ORBI little dance, all of them are mostly shot in close-ups and there is a little "cheap" feeling about all this, like a bad short-feature horror film. On the other hand, it's nice enough to have integrated digitized actors in the first place in this day and age.

On the sound department, the whole ambiance is great and the music is pretty nice (even if it could have benefited from a little more tracks because it tends to repeat itself pretty quickly). The sound effects have nice swishes and swooshes that add to the magical theme and all of this is of pretty good quality overall.

Final Score : 5. Pretty good overall but a few hits and misses in the design department. Good music though.

Environment and Atmosphere

Despite the odd design choices and a few elements that I could easily have done without (UKI, ORBI and your little dance, I'm looking at you), if there is something that you can't reproach Ween : The Prophecy for, is its atmosphere. The whole game is full of magic, weird things and every new screen is an invitation to explore and find what new kinds of surprises the game holds for you. The mysterious statues that are found everywhere, the magical beings you're encountering… Add to that the whole sunset/moonlight feeling that you have for most of the game and you have the feeling of a magical world ending.

When the sun in the sky looks like this, it's time to go to the nearest shelter

The use of colors is also to be commended. The whole game is painted in dominant colors (mainly orange and purple) and it really adds to the atmosphere (despite a few clashes here and there).

However (because we always need a however), once again, a few choices go against the whole thing. There is sometimes goofiness that would be more in its place in a Gobliiins game, sometimes alternating immediately with something more mysterious. I think the developers were trying to alternate between mysterious and funny, but it sometimes doesn't work. Managing a "hot and cold" ambiance (like, let's say, the early movies of Tim Burton, for example) is something that's really hard to achieve and I can't help but feel like the developers should have chosen a direction and stick with it instead of trying to alternate between serious and goofy.

Final Score : 6. Great magical atmosphere, marred sometimes by odd goofy moments.

Dialog and Acting

Like I've said earlier, a lot of the exposition text and dialog is pretty nonsensical. Sometimes, the ORACLE or the BORGOL (whatever the latter is) appear and tell you a lot of things, much of it not making a lot of sense… Some other times, OHKRAM appears and tells you you've gained a grain of sand even if you weren't really trying to do so… Most of the interactions with the animals and sentient beings you cross path with are nice without being really noteworthy.

The exception to this rule is URM, your vampire buddy, which is the most competently written character. His lines are sometimes funny, especially when you call him for no reason. He's helping and mocking in equal measures and is a pretty good sidekick.

And he really seems to enjoy doing evil deeds, which is a good thing in my book

The rest of the sidekicks are not that great. PETROY spends most of the time telling you "he can't tell you anything about that" when you ask him for help, but sometimes, he drops a clue that's mandatory to understand the puzzles. And I think I've rambled enough on UKI and ORBI, but let's say that every time their ugly mugs appear, you know you're here for what appears like full minutes listening to their stupid dances and songs. And the fact that you can't speed up the dialog doesn't help, especially if you reload to earlier stages of the game you've already suffered through.

The acting in itself is mainly digitized people in Halloween masks waving and doing over the top gestures to make their point, so it's nothing to write home about. At least, the final animation of KRAAL apparently trying to peel his face off is satisfactory enough.

Final Score : 4. Apart for URM, nothing really stands out, and the twins are consistently cringeworthy.

Final Score

So without further ado, the final score equals (6+4+3+5+6+4/0.6) = 47! I'll add one discretionary point for the fact that, despite all its quirks and errors, the whole experience was overall pretty pleasant and I think it'll stick with me as a good memory. And I realize now that doing so gives it the exact same score of the first Gobliiins and five points above The Legend of Djel, so kudos to Coktel for upping their game since Bargon Attack and Emmanuelle!

Congrats on your score guess, Lugh, you earn CAPs!


I'm glad I was able to finally play through this game. I had memories of it for a long time ago and being able to make some real progress on it instead of being stuck on the second screen like the stupid kid I was made me feel like an achievement! See you around and thank you all for your attention and your comments!

CAP Distribution

100 CAPs to Alfred n the Fettuc
  • Blogger Award - 100 CAPs - for playing through Ween for everyone's enjoyment
115 CAPs to Joe Pranevich
  • Vohaul Award - 5 CAPs - for letting us know that Infamous Adventures have just released a new version of Space Quest II
  • Festive Blogger Award - 60 CAPs - for blogging through A Christmas Adventure with a bonus interlude for everyone's enjoyment
  • Classic Blogger Award - 50 CAPs - for blogging through Crash Dive for everyone's enjoyment
105 CAPs to Ilmari Jauhiainen
  • Djel Historian Award - 5 CAPs - For giving us worrying details about DJEL and AZEULISSE real relationship
  • Classic Blogger Award - 50 CAPs - for blogging through Growing Pains of Adrian Mole for everyone's enjoyment
  • Classic Blogger Award - 50 CAPs - for blogging through The Price of Magik for everyone's enjoyment
70 CAPs to Will Moczarski
  • Classic Blogger Award - 50 CAPs - for blogging through The Institute for everyone's enjoyment
  • Intermission Award - 20 CAPs - for a 1981 Summary of Med Systems Software
51 CAPs to Vetinari
  • True Companion Award - 20 CAPs - for playing along
  • Alternative Award - 6 CAPs - for giving hints about the alternative paths
  • The Ball and the Cauldron Award - 5 CAPs - for agreeing with my rambling about the copper ball transformation and alerting me about the potion mixing nightmare.
  • Psychic Prediction Award - 10 CAPs - for  being the closest guesser to the Price of Magic PISSED rating
  • Psychic Prediction Award - 10 CAPs - for correctly guessing The Institute's PISSED rating
32 CAPs to MorpheusKitami
  • True Companion Award - 20 CAPs - for playing along.
  • Back Of His Hand Award - 5 CAPs - for sharing his interesting insight on a game that he knows very well
  • Djel and Azeulisse Award - 5 CAPs - for guessing that Djel and Azeulisse were probably deadbeat parents
  • Alternative Award - 6 CAPs - for giving hints about the alternative paths
  • Size Does Matter Award - 5 CAPs - for engaging in a discussion about the two stupid twins real size
  • Lost Bet Award (Unaward?) - -10 CAPs - For betting against me that I wouldn't find the answer to the snake puzzle
  • Ho Ho Oh... Award - 1 CAP - for remembering a Christmas game we could play... but not knowing we'd already played it
20 CAPs to Mr. Sack
  • What's Your Story Award - 20 CAPs - for submitting his answers to our What's Your Story questions
15 CAPs to Lugh
  • Psychic Prediction Award - 10 CAPs - for correctly predicting the PISSED rating
  • Gene and Dean Award - 5 CAPs - for telling us about the Ween band that might have (or not) something to do with the title change
10 CAPs to Rowan Lipkovits
  • 33 and 1/3 Award - 5 CAPs - for the surprising news that games have actually been distributed on vinyl records
  • Do Androids Dream of Kindle Paperwhites Award - 5 CAPs - for knowing how reading in dreams works
10 CAPs to ShaddamnIVth
  • Minotaur Award - 5 CAPs - for actually programming a labyrinth while studying
  • Do Androids Dream of Kindle Paperwhites Award - 5 CAPs - for knowing how reading in dreams works
5 CAPs to Jonathan
  • The Doctor Is In Award - 5 CAPs - for giving us chilling details about the digitalis and its effect on rats
5 CAPs to Deano
  • Cold As Balls Award - 5 CAPs - for letting Ilmari know the likely background to the brass monkey puzzle in Price of Magik
    5 CAPs to Andy_Panthro
    • Alchemist Award - 5 CAPs - for finally explaining to me why people bite gold
    5 CAPs to Laukku
    • Pixel Filtering Award - 5 CAPs - for alerting me that my emulation software was filtering pixels
    5 CAPs to Mayhaym
    • Wario Ware Award - 5 CAPs - for appreciating that sometimes you need to pick the nose of a demon dog
    5 CAPs to Corey Cole
    • Rutabaga Award - 5 CAPs - for answering Will's question, and adding more historical context to a character from The Institute
    5 CAPs to Lisa H.
    • The Shape of Watercraft Award - 5 CAPs - for pointing out that all submarines are long, thin and full of seamen

      CX 2690, Pengo!

      This episode is all about the very cute Sega arcade game Pengo, as ported by Atari. Not by GCC, which is surprising for this time period. I hope that you enjoy the episode. Next up is Crackpots by Activision. If you have any thoughts on Crackpots, please get them to me at 2600gamebygame@gmail.com by 6 PM EST on 5 February.

      Thank you for your patience, and for listening.

      Pengo on Random Terrain
      Pengo on Atari Protos
      Pengo on KLOV
      Mark Hahn interview by Scott Stilphen
      Mark Hahn's web site
      Andrew Fuchs' web site
      Courtney Granner on San Jose State web site (features some artwork)
      1984 Atari dealer catalog on Atarimania
      Jim's hack of 2600 Pengo with Popcorn!
      Pengo arcade soundtrack on Youtube
      No Swear Gamer 299 - Pengo
      Arcade USA - Pengo minisode
      Atari 5200 Super Community Podcast - Pengo
      Memory Machine Podcast - Christmas Menagerie
      Gen X Grown Up Podcast

      Oceanhorn 2 Demo In Nordic Game 2017!


      It is news time! Oceanhorn 2: Knights of the Lost Realm will make a gameplay debut with a playable demo in Nordic Game 2017!

      If you are coming to Malmö, head to Epic Games' booth and come and see what we have in store for the new Oceanhorn game! So whether you're a fan, a journalist, a publisher or a fellow game developer – we would be delighted to give you a tour on our game and talk more about Oceanhorn 2.

      Oceanhorn 2: Knights of the Lost Realm is a continuation to Oceanhorn: Monster of Uncharted Seas, a million selling action RPG title released for iOS, Mac, Steam, PS4, Xbox One, Android and later this year for Nintendo Switch. Oceanhorn 2 is powered by the unrivaled Unreal Engine 4.

      Nordic Game 2017 17-.19.5. in Malmö, Sweden.
      http://conf.nordicgame.com/

      We could not be more excited about Nordic Game ourselves. In addition to Oceanhorn 2's big moment, Fumito Ueda is also going to be in Malmö! He is the mastermind behind Ico, Shadow of the Colossus and The Last Guardian and we are big fans of his work. It seems like Action RPG's are only now starting to catch up what Shadow of the Colossus did 12 years ago. The carefully crafted spirit of his games and the brilliance of his game designs are a driving force for game developers like us.

      Follow with Bloglovin

      Thursday, March 5, 2020

      Thinking About Game Design

      I found this excellent graph in @joebaxterwebb's site. It's a synthetic and great game design lesson to think before gaming development. You can read the complete article HERE.

      Sure I'll use in my game designing classes next semester. =)



      Thanks, Joe for this great content.

      #GoGamers