Romance of the Three Kingdoms XI game event stills

In Koei’s Romance of the Three Kingdoms XI for Windows PC (non PUK, English edition), there are a total of 30 event stills ( basically, pictures of important events during a campaign, viewable under Settings -> Reference -> View Event Stills ). Upon collecting all 30 and winning any scenario to unite China, you will unlock top-tier skill sets and all historical portraits when you use Create Officer for your own custom officers. It’s one of the things required for One Hundred Percent Completion of the game. However, there has not been a very good guide as to how to achieve all 30 events, especially with problematic and rare ones like Secret Meeting.

This post is my attempt to catalog all the event stills and how to obtain them in game. The events are listed below in order of their appearance on the View Event Stills page. In general, you only need to view the Event Still once. That means that you can start a game, obtain the Events you want, without actually completing or even saving the game once. Even if you abandon that game later, once you’ve viewed the event, it counts toward your completion of collecting all 30.

Note that I will not suggest any unreasonably contrived means to get events, even if that might be faster, because I consider these tactics basically cheating. For example, I will not suggest that you send your sovereign out to die deliberately to get the Sovereign Death event, even if you might be able to do that. You may also create officers with birth and death dates to your exact specification, to achieve some of these events, but that, too, is basically cheating. Most of the fun in these events is trying to obtain them fairly while playing a game — it adds an additional dimension of strategic planning. If you’re just going to cheat, stop reading this and go download the fully unlocked sysfile that’s floating around the Web.

Page 1

  • Plague – when a city receives a Plague event, causing all sorts of havoc. You will likely get at least one in any scenario.
  • Locusts – when a city receives a Locusts event, decreasing food production in that city. You will likely get at least one in any scenario.
  • Plenty – when a city receives a Plenty event during harvest season, increasing food production in that city. You will likely get at least one in any scenario.
  • Bandits – when bandits appear in your territories, as the name suggests. The easiest way to obtain this still is to start the Yellow Turban Rebellion scenario. During the story intro sequence, the Yellow Turbans will rise against the Han court, and this will unlock the event still.
  • Coronation – when an Emperor is crowned, or when you declare support for the Emperor after capturing the capital (Luoyang, Chang’an, or Xu Chang, depending on the scenario). Easily achievable in most scenarios if you’re winning.
  • Unity: Male – when you unite China under a male sovereign. This event will be unlocked when you win a scenario with a male sovereign. I prefer Liu Bei, but YMMV 🙂
  • Unity: Femalenotes not yet available
  • Downfall – when one of the forces in the game is eliminated. At least one ruler will fall in any game, so this is trivial to obtain. You can also get this by losing your city in Tutorial 3, Going into Battle.
  • Independence – when a prefect or viceroy declares independence and forms his or her own force in a game. In Tutorial 6, Capturing Cheng Du, there is a good chance that Jian Ning will declare independence under the prefect Yong Kai, but it is not guaranteed. In the 190 scenario, the free cities in Jiangdong may declare independence under their prefects within the first two years. In any scenario, foment an independence movement in an enemy city via the strategy Collaborate. Alternatively, wait until one of your district viceroys’ or city prefects’ loyalty falls below a certain threshold, at which point an AI force is likely to foment a revolt in that prefecture or district. Finally, when you’re winning a full scenario, at the very end of the game one of your officers will ask you to investigate another officer for treason. If you choose to do so, that officer will be proven innocent, but will revolt anyway due to your distrust of him. This revolt will trigger an Independence event.
  • Omen – This event is displayed at the start of the year, when your strategist warns that one of your officers is about to die (of natural causes, not in battle). If you play through a game with historical age settings, quite a few of your officers will die. Pick a middle scenario, when there are a lot of older officers around.
  • Sovereign Death – when your own sovereign dies of natural causes. The easiest way to get this one, short of deliberate regicide on your part, is to use Tao Qian in 194, Rival Warlords. He will most likely die within the next two years, giving you this event.

Page 2

  • Officer Death : Male – When one of your male officers die. This is relatively trivial to get – one will come within the year, after an Omen, for example. Your officer may also be killed by a cavalry charge or in a duel, if officer deaths are on.
  • Officer Death : Female – When one of your female officers die. This is a little more annoying, given the sparsity of female officers. Still, at least one should die in any game. Your officer may also be killed by a cavalry charge or in a duel.
  • Funeral – When any sovereign (except yours) dies of natural causes — that is, of illness or old age, not in battle. In the 194 scenarios, Tao Qian will die within the next two years. Play the scenario as a ruler other than him, and you will trigger this event still.
  • 2 Sworn Brothers – when you arrange for two male officers to swear brotherhood with each other. Officers with sworn brothers on the same force will not defect, and will obtain bonuses when both are assigned to the same unit. You’ll need two officers of the male gender and at least 500 in Deeds each. You will also need 500 technique points (TPs). At that point, Sovereign -> Mediate will allow you to mediate sworn brotherhood between these two officers and unlock this event.
  • 2 Sworn Sisters – when you arrange for two female officers to swear sisterhood with each other. Officers with sworn sisters on the same force will not defect, and will obtain bonuses when both are assigned to the same unit. You’ll need two officers of the female persuasion and at least 500 in Deeds each. You will also need 500 technique points (TPs). At that point, Sovereign -> Mediate will allow you to mediate sworn sisterhood between these two officers and unlock this event.
  • Male Officer Appears – Triggers at the start of a new year, when a male officer (who is related to one of your current officers) arrives to offer his services to your ruler. For example, as Liu Bei in 211 Liu Bei in Shu scenario, you will likely receive Zhang Bao – Zhang Fei’s son, in 212. Note that your sovereign should be within a city for this event to occur.
  • Marriage – when you marry one of your officers to another – married officers will not defect, and obtain bonuses when assigned to the same unit. You’ll need two officers of opposite gender, at least 500 in Deeds, and unmarried status. You will also need as 500 technique points (TPs). At that point, Sovereign -> Mediate will allow you to conduct a marriage between these officers and unlock this event.
  • Fem. Officer Appears – Triggers at the start of a new year, when a female officer (who is related to one of your current officers) arrives to offer her services to your ruler. This one is fairly tricky, because there aren’t that many female officers. In general, play one of the middle scenarios as a prominent family. For example, if you play as Sun Quan in 211, you will get a female officer from the Sun family in 215.
  • Resignation – when an officer resigns from your force due to low loyalty. This is also a hard one to get if you are a decent player, since you’d never let an officer’s loyalty drop low enough. Note that if your sovereign dies and your officers resign, you will not receive this event still. You must have this officer resign through low loyalty. Officers with loyalty less than 70 will tend to resign, and they usually do so on Jan of a new year. Best way to do this may be to play as Dong Zhuo in 190. Use your overwhelming starting forces to take down Cao Cao, then hire his wife Bian Shi. Use Bian Shi to hire Cao Cao. Dong Zhuo and Cao Cao are disliked officers, so Cao Cao’s loyalty will start in the 70s and drop fast. However, since you have his wife in your service, he will not be hired away by another sovereign. At the start of the next year, Cao Cao will most likely resign from your force.
  • Decree – when an imperial decree arrives. For example, when the Emperor promotes your sovereign to the rank of Duke, he will use this kind of decree. Since to win a game, you’ll likely surpass the rank of Duke, this event is trivial to unlock if you win a game.
  • Orders – when a different type of imperial order arrives. If you start 190 Cao Cao's Ascent, the story intro sequence to the scenario involves Cao Cao’s forged imperial edict arriving at Yuan Shao’s city. This will grant you the event still.

Page 3

  • Fallen Castle – when a city falls to your forces. You are likely to receive this in Tutorial 6, Capturing Cheng Du…when you capture Cheng Du. Otherwise, take any city or base, and the event is yours. Trivial.
  • Conversation – when one of your civil officers head off to search for a friend in the area and obtains his or her services after a debate. This seems to occur randomly, when your sovereign is in the same city as certain civil officers on his force. It is the analogous event to “Search”, which applies only to military (high WAR) officers. The event represents the “conversation” between your officer and his friend. This obviously only triggers when there are hidden officers to find in a city — so start an early scenario with lots of hidden officers for a better shot at the event.
  • Coalition – pick up this event when the coalition against Dong Zhuo forms in 190 Cao Cao's Ascent, at the very beginning during the story intro sequence. Otherwise, play as a strong army (say, Cao Cao in 207), and eventually two of your weaker enemies will merge to form a coalition against you.
  • Search – when one of your military officers head off to search for a famous hero in the area and obtains his or her services after a duel. This seems to occur either randomly or scripted to resemble randomness. This obviously only triggers when there are hidden officers to find in a city — so start an early scenario with lots of hidden officers for a better shot at the event. The 190 scenario with Cao Cao in Xu Chang or Chen Liu should be an easy way to get this event, as you recruit various notables like Dian Wei or Xu Chu.
  • Secret Meeting – when you meet a hidden character for a philosophical discussion. This one is ridiculously obscure and difficult to obtain, to the effect that many people do not know how to obtain it. Forum posts and such suggest that you’d receive this when the AI foments unrest with one of your viceroys or prefects (one of the in-game log messages say “your prefect blah is meeting someone secretly”. However, that is a red herring. One post correctly identifies that the Secret Meeting event is awarded for meeting a hidden character such as Xu Shao during a Search. As Cao Cao in 190 Cao Cao's Ascent, if you keep Searching the area around Chen Liu or Ru Nan, against your strategist’s advice that nothing would be found, you will eventually encounter Xu Shao, who will do a physiogamy reading for you, unlocking this event. One of the early scenarios, such as Rise of Dong Zhuo, is preferred for obtaining this event. Just keep Searching your city, a lot, and fruitlessly most of the time. You’ll get this eventually ( took me under two game years of on-and-off searching in Chen Liu while holding off Dong Zhuo’s army ). A comment from Lance Lidner reports that using Kong Zhou in Rise of Dong Zhuo works best, as Xu Shao appears in Ru Nan at that time. Kong Zhou is also out of immediate reach from most hostile factions in that scenario, so you can afford to take your time.
  • Appoint – when the emperor issues a new title to you. This occurs when you’ve captured enough cities to reach the next rank, and that your sovereign is currently in a city (as opposed to being on campaign). As Liu Bei in the 211 Liu Bei in Shu scenario, taking Xiang Yang (via Jiang Ling – you’ve got Zhuge Liang, Pang Tong, Zhang Fei, Liu Bei, Sun Shang Xiang, Zhao Yun … that’s plenty to take the city from Cao Ren early on) and Yong An will bump you up to Field Marshal, and Emperor Xian will award you the title and this event. As Cao Cao in 190 Cao Cao's Ascent, taking the free cities of Xu Chang and Xin Ye will grant the title of Lt. Governor, which once again easily unlocks this event.
  • 3 Sworn Brothers – when you arrange for three male officers to swear brotherhood, much like the historical Oath of the Peach Garden of Liu Bei, Guan Yu, and Zhang Fei. Officers with sworn brothers on the same force will not defect, and will obtain bonuses when two or more are assigned to the same unit. You’ll need three officers of the male gender and at least 500 in Deeds each. You will also need 500 technique points (TPs). At that point, Sovereign -> Mediate will allow you to mediate sworn brotherhood between these officers and unlock this event.
  • 3 Sworn Sisters – when you arrange for three female officers to swear sisterhood. Officers with sworn sisters on the same force will not defect, and will obtain bonuses when two or more are assigned to the same unit. You’ll need three officers of the female persuasion and at least 500 in Deeds each. You will also need 500 technique points (TPs). At that point, Sovereign -> Mediate will allow you to mediate sworn sisterhood between these officers and unlock this event. The hardest part of this is rounding up 3 female officers to begin with.

redhillonrails_core and broken MySQL empty string defaults

While hacking on a side project in Ruby on Rails, I ran across this weird error when trying to insert new data:

ActiveRecord::StatementInvalid: Mysql::Error: Column 'attr2' cannot be null: INSERT INTO `foo` (`attr1`, `attr2`) ... VALUES ('1', NULL)

where attr2 is a varchar (or t.string, in Rails lingo) and set to not null default '' (or, in other words, :null=>false, :default=>''). Strangely enough, instead of the default value of ”, ActiveRecord was setting the value to nil instead, which translates into a NULL. Since the schema explicitly forbids NULLs on that column, the statement explodes.

After an hour of poking around and hacking up a spike solution, it turns out a plugin was to blame. I’d pulled in the foreign_key_migrations plugin (a highly recommended add-on) to automatically install foreign key constraints (in this day and age, the foremost web framework still can’t automatically handle FOREIGN KEY constraints, the most basic tool for ensuring data integrity in relational databases, for its migrations? Bah!).

This plugin has a dependency on redhillonrails_core, which has a known bug: Incorrectly overwrites mysql empty-string default with nil for string/text/binary types.

The bug is apparently not being worked on as of the time of this writing. The dev doesn’t consider this a bug, as he claims that “[he considers] empty strings to be semantically identical to NULL”.

This position, unfortunately, is not supported by the SQL standard. Wikipedia has a section on common SQL NULL mistakes documenting some of the potential problems involved in making such an assumption. Philip Greenspun has further notes on this. Using NULLs trigger the all the arcane annoyances of three-valued logic, and you must be prepared to consider True, False, and NULL values as comparison outcomes. Someone not very versed in three-valued logic can easily cause a number of subtle mistakes trying to compare values.

To workaround this bug, you will need to comment out the initializer function in

vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/mysql_column.rb

Alternatively, you can delete the file, and remove relevant references to it..

If you agree with dev’s position that NULLs are “semantically identical” to empty strings, remember to pay attention when you formulate your SQL queries (and when Rails formulates those queries) — your results may not be what you expect, if implemented naively. Get your three-valued logic truth tables out 🙂

APR and 32-bit/64-bit universal binary compilation

When compiling APR, the Apache Portable Runtime 1.3.3 (as a part of Subversion 1.5.3 as I am doing here, or not) on OS X 10.5 Leopard, you may encounter the following error at compile time.

/bin/sh /tmp/subversion-1.5.3/apr/libtool --silent --mode=compile gcc-4.2 -Os -arch i386 -arch x86_64 -DHAVE_CONFIG_H -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -no-cpp-precomp -I./include -I/tmp/subversion-1.5.3/apr/include/arch/unix -I./include/arch/unix -I/tmp/subversion-1.5.3/apr/include/arch/unix -I/tmp/subversion-1.5.3/apr/include -o strings/apr_snprintf.lo -c strings/apr_snprintf.c && touch strings/apr_snprintf.lo
strings/apr_snprintf.c: In function ‘conv_os_thread_t’:
strings/apr_snprintf.c:500: error: duplicate case value
strings/apr_snprintf.c:498: error: previously used here
strings/apr_snprintf.c: In function ‘conv_os_thread_t_hex’:
strings/apr_snprintf.c:671: error: duplicate case value
strings/apr_snprintf.c:669: error: previously used here

This will most likely happen when you are configured to build a dual 32-bit / 64-bit universal binary, whether it be ppc / ppc64, or i386 / x86_64, or any permutation thereof. This ticket over at MacPorts documents a particular instance of this problem, with no apparent solution.

The symptom is easy to explain. Somehow, two case labels in the relevant switch statement in strings/apr_snprintf.c:500:

switch(sizeof(u.tid)) {
    case sizeof(apr_int32_t):
        return conv_10(u.u32, TRUE, &is_negative, buf_end, len);
    case sizeof(apr_int64_t):
        return conv_10_quad(u.u64, TRUE, &is_negative, buf_end, len);
    default:
        /* not implemented; stick 0 in the buffer */
        return conv_10(0, TRUE, &is_negative, buf_end, len);
    }

have evaluated to the same value. In particular, it believes that sizeof(apr_int32_t) and sizeof(apr_int64_t) are the same value. As we all know in C, you cannot have two identical case labels in the same switch statement. However, the root of the problem is a bit more subtle.

In $SRCDIR/include/apr.h, you’re likely to see this fragment of code.

typedef  long       apr_int64_t;
typedef  unsigned long  apr_uint64_t;

Notice that it has typdef’ed apr_int64_t as a long and apr_uint64_t as unsigned long. This is because at configure time, the script detected that long values are 64-bit on this system, so it assigned the apache 64-bit types to longs. However, this only holds true for half of the compilation – because you are building a universal binary for a 32-bit architecture as well. Remember that in 32-bit GCC on OS X, longs are 32-bit rather than 64-bit. Your run-of-the-mill autoconf script, done by a non-OS X programmer, isn’t going to be able to detect this subtlety – if the 64-bit part worked, it’ll keep thinking longs are 64-bit, end of story – and happily generate the incorrect typedef expressions. When you apply sizeof to these types in apr_snprintf.c, both evaluate to 4 bytes under 32-bit compilation, thus blowing up the compile run.

To truly fix the root of the problem requires rewriting the autoconf script to detect Mac OS X and its universal binary building, which can potentially throw quadruple architectures at the same compilation script. However, a quick hack to make this particular problem go away is to change apr.h such that:

typedef  long long       apr_int64_t;
typedef  unsigned long long apr_uint64_t;

Now that we ensure in either 32-bit or 64-bit compilation, apr_int64_t and apr_uint64_t are always typedef’ed to appropriate, guaranteed 64-bit types. The compilation of APR (and Subversion) will proceed normally.

Note that long long is not an standard C type. As a GCC extension, this fix is a kludge. A kludge that works (for me), though.

UPDATE:
There may also be an issue with sizeof definitions that may cause the library to crash. In particular, there may be occurrences of

#define APR_SIZEOF_VOIDP 8

that were generated by configure. To fix this, you will need to remove the define and have the compiler check for 64-bit at compile-time:

#ifndef __LP64__
    #define APR_SIZEOF_VOIDP 4
#else
    #define APR_SIZEOF_VOIDP 8
#endif

In general, any predefined sizeofs need to be changed. I am not sure why the APR developers do hard-coded defines like this, given that the point of having sizeof() calls is to avoid such issues.

using ffmpeg for cutting media files – and the gotchas involved

So here I was, trying to complete some ordinary transcoding / media file cutting tasks with ffmpeg. Turns out there are some weird gotchas when using some versions of ffmpeg (in my case, SVN-r10571) on the commandline.

Problem 1: transcoding to mp3 insists on using 64kbits/s or 128kbits/s bitrate

So a simple task is to transcode an audio file of some arbitrary format to MP3. In my case, I only wanted a 30-second piece of the original file, converted to MP3. The original was in 256kbits/s, and I decided to use the same bitrate for the output, just for kicks. Reading the man page, -b is for video bitrate, and -ab is for audio bitrate. So I executed:

wrong:  ffmpeg -ss 00:00:30.00 -t 25 -i foo.mp3 -ab 256 foo-new.mp3

The output, of course, was this:

Input #0, mp3, from 'foo.mp3':
...
mdb:109, lastbuf:0 skipping granule 0
size= 393kB time=25.2 bitrate= 128.0kbits/s
video:0kB audio:393kB global headers:0kB muxing overhead 0.007950%

128 kbits/s. That was…not what I wanted.

Turns out, as the ffmpeg man page hints but does not specify clearly, a “k” is required to label the units of the new bitrate. As in:

right:  ffmpeg -ss 00:00:30.00 -t 25 -i foo.mp3 -ab 256k foo-new.mp3

This time, the output was:
Input #0, mp3, from 'foo.mp3':
...
mdb:109, lastbuf:0 skipping granule 0
size= 782kB time=25.0 bitrate= 256.0kbits/s
video:0kB audio:782kB global headers:0kB muxing overhead 0.003996%

Much better. It’s very strange how that if I don’t give it the ending “k” but do give it a higher value than 64, it always bumps up the bitrate to 128kbits/s, from the default of 64k (but not to the number I actually wanted).

 

Problem 2: cutting media file without re-encoding

So ffmpeg can be used to cut a media file, without reencoding the media stream. You simply pass the raw copy codec to the -acodec (or the -vcodec for video) at encode time. For my MP3, I thought it was a pretty trivial problem, so I issued:

wrong: ffmpeg -i bar.mp3 -ss 00:00:30.00 -t 25 -acodec copy bar-new.mp3

This seemed to process correctly, except it created a 555-byte empty file with no content in it. What’s even weirder, if you issued:

wrong: ffmpeg -i bar.mp3 -ss 00:00:10.00 -t 25 -acodec copy bar-new.mp3

That is, -ss 00:00:10.00 to seek to the 10th second, and -t 25 to record 25 seconds worth of audio. Strangely enough, the output file had 15 seconds of audio, the subtraction of 25 by 10. Curiouser and curiouser. Now,

wrong: ffmpeg -i bar.mp3 -ss 00:00:10.00 -t 25 -acodec mp3 bar-new.mp3

does in fact create a 25-second MP3 file. Only, of course, a re-encoded one at 64kbits/s. Something that we are not looking for. But strange.

A post on ffmpeg-devel finally provided enough hints to clue me into the problem. Unlike many command line apps, the order of arguments passed to ffmpeg seem to be silently significant. The correct incantation is:

right: ffmpeg -ss 00:00:30.00 -t 25 -i bar.mp3 -acodec copy bar-new.mp3

Note the switched order for the arguments -i and the args -ss and -t, where the -i must follow the other two. Now, the desired 25-second file, cut from the original, is correctly produced.

When arguments are missing some arbitrary text or in the wrong order, ffmpeg doesn’t sanity-check or warn you of these…it just silently proceeds and does some very strange things. Things that make you scratch your head and wonder, “wtf? did I mistype an argument somewhere?”

Ah, and of course, you make me have to track down all these little idiosyncrasies, wading through blog posts and mailing lists and forums. Agh.