<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Making Games the Hardest Way Possible</title>
	<atom:link href="http://lthzelda.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://lthzelda.wordpress.com</link>
	<description>A Demo of an Idea</description>
	<lastBuildDate>Tue, 24 Jan 2012 09:29:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='lthzelda.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Making Games the Hardest Way Possible</title>
		<link>http://lthzelda.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://lthzelda.wordpress.com/osd.xml" title="Making Games the Hardest Way Possible" />
	<atom:link rel='hub' href='http://lthzelda.wordpress.com/?pushpress=hub'/>
		<item>
		<title>[REV-2] A Hot-Off-The-Press Hack Update!</title>
		<link>http://lthzelda.wordpress.com/2010/09/08/rev-2-a-hot-off-the-press-hack-update/</link>
		<comments>http://lthzelda.wordpress.com/2010/09/08/rev-2-a-hot-off-the-press-hack-update/#comments</comments>
		<pubDate>Wed, 08 Sep 2010 07:09:47 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=348</guid>
		<description><![CDATA[Blog Info: Looking at my blog&#8217;s statistics, I get the most hits for Hyrule Magic articles. RPG Maker &#38; Eternal Lands are next, and nobody seems to read my REV series on interesting hacks. Which leads us to the back-story&#8230; &#8230; <a href="http://lthzelda.wordpress.com/2010/09/08/rev-2-a-hot-off-the-press-hack-update/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=348&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em><strong>Blog Info: </strong>Looking at my blog&#8217;s statistics, I get the most hits for Hyrule Magic articles. RPG Maker &amp; Eternal Lands are next, and nobody seems to read my REV series on interesting hacks. Which leads us to the back-story&#8230; </em></p>
<p><strong><em>Back-story:</em></strong> I was hard at work on my next Hyrule Magic blog entry, which was a lot easier thanks to all your excellent &amp; intelligent comments. (Thanks readers!) But then, I stumbled across <a href="http://board.byuu.org/viewtopic.php?f=9&amp;t=934"><strong><span style="color:#0000ff;">this post</span></strong></a> in byuu&#8217;s forum. I&#8217;ll explain it as we go along, since the linked post only contains half the story.</p>
<p><strong><em>Super Mario Odyssey 2 &#8212; Now with MSU1 !</em></strong><br />
<span style="text-align:center; display: block;"><a href="http://lthzelda.wordpress.com/2010/09/08/rev-2-a-hot-off-the-press-hack-update/"><img src="http://img.youtube.com/vi/zbp1nQpZpfM/2.jpg" alt="" /></a></span><br />
<strong>Summary:</strong> Years ago, BMF54123 suddenly stopped working on Super Mario Odyssey. This made me sad. Then, just last week, I found a post stating that he&#8217;d re-started it, and had utilized byuu&#8217;s amazing new MSU1 chip to put near-CD-quality audio into the hack.</p>
<p><em><span style="color:#ff0000;"><strong>Wait, that audio&#8217;s real!?!?</strong></span></em></p>
<p><strong>Technology:</strong> Yes, the sound on that video is exactly what you would hear if you plugged the Super Mario Odyssey cart into a SNES and turned it on. There are some caveats; for example, the MSU1 is only emulated by <a href="http://byuu.org/bsnes/"><strong><span style="color:#0000ff;">bsnes </span></strong></a>at the moment. Also, actually making a &#8220;Super Mario Odyssey cart&#8221; is not possible  &#8211;although byuu is making a hardware implementation of the MSU1, so it will be possible in the future. That said, most gamers only play hacks on emulators anyway, so the fact remains: <em>if you play SMW Odyssey on bsnes, expect awesome music</em>!</p>
<p><strong>Other notes: </strong>I really like the short &#8220;intro&#8221; story, showing how Bowser might have ended up with all the crazy time-travel technology that caused the Odyssey in the first place. Also, I like how the game starts with a simple &#8220;intro&#8221; level (like Yoshi&#8217;s island), and I like the &#8220;File Select&#8221; menu. BMF54123 certainly fine-tuned his ASM skills in the intervening years. (According to the SMW Central forums, he decided to rewrite from scratch because his original code was an undocumented mess.)</p>
<p><strong>What this means: </strong>I&#8217;d like to think that this hack will usher in a new era of good hacks with rich environments backed up by nice ambient music. However, it&#8217;s equally likely to generate hacks of poor quality that are now multi-megabyte patches due to useless MP3 from popular bands.</p>
<p><strong>Why I&#8217;m Excited: </strong>I haven&#8217;t been this excited for a hack in a while &#8211;it rivals my <a href="http://www.questforcalatia.net/Zelda3C"><strong><span style="color:#0000ff;">Quest for Calatia</span></strong></a> obsession! In fact, the MSU1 has nothing to do with this  &#8211;I&#8217;m really just excited that Super Mario Odyssey&#8217;s excellent level design and intriguing world design will carry over into a new hack. I&#8217;ve always felt that BMF54123 understands what makes a good hack more than most people, and his inclusion of high-quality audio is just icing on the cake.</p>
<p><strong>Your Homework: </strong>Watch the video again, and try to pay attention to the level design of the intro level. Even though this is likely just a demo level, it&#8217;s very balanced, and far above some hacks&#8217; release-quality levels.</p>
<p><strong>My Homework: </strong>Work on a blog post!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/348/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/348/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/348/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/348/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/348/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/348/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/348/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/348/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/348/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/348/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/348/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/348/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/348/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/348/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=348&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2010/09/08/rev-2-a-hot-off-the-press-hack-update/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>
	</item>
		<item>
		<title>[RM-4] TCP Sockets in RPG Maker VX</title>
		<link>http://lthzelda.wordpress.com/2010/04/28/rm-4-tcp-sockets-in-rpg-maker-vx/</link>
		<comments>http://lthzelda.wordpress.com/2010/04/28/rm-4-tcp-sockets-in-rpg-maker-vx/#comments</comments>
		<pubDate>Wed, 28 Apr 2010 06:28:31 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=250</guid>
		<description><![CDATA[Blog Info: I was in a bit of a slump lately for new post ideas –it seemed that all my good ideas were far too big, and I didn&#8217;t really want to get side-tracked like I did for the EL &#8230; <a href="http://lthzelda.wordpress.com/2010/04/28/rm-4-tcp-sockets-in-rpg-maker-vx/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=250&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em><strong>Blog Info</strong></em><strong>:</strong> I was in a bit of a slump lately for new post ideas –it seemed that all my good ideas were far too big, and I didn&#8217;t really want to get side-tracked like I did for the EL client notifier. So, I decided to look into the possibility of doing networked games using <a href="http://en.wikipedia.org/wiki/RPG_Maker"><span style="color:#0000ff;"><strong>RPG Maker</strong></span></a>. Along the way, I finally found a good way to highlight code samples on this blog &#8211;by using Scite&#8217;s &#8220;Export to HTML&#8221; feature!</p>
<p><em><strong>Back-story</strong></em><strong>:</strong> When RPG Maker VX came out, it radically changed the organization of <a href="http://ruby-lang.org/"><span style="color:#0000ff;"><strong>Ruby</strong></span></a> code internal to the engine. What it did not change was the fundamentals of the scripting system itself. Thus, any code in RPG Maker XP could feasibly run on VX –assuming that it made no reference to windows, sprites, etc. Unfortunately, porting this code was not always easy. One module that never made the transition was the <a href="http://www.rpgrevolution.com/forums/index.php?showtopic=35936"><span style="color:#0000ff;"><strong>RPG Maker XP Online System</strong></span></a>, programmed by username “Blizzard”. This system was a beautifully designed, fully-functional API for RPG Maker network play. Fortunately, Blizzard released the source code for this engine under the Creative Commons (NC-SA) license. This first entry will deal with the simplest –but most important– problem: using sockets. After that, we will slowly build up.</p>
<p><em><strong>Goal</strong></em><strong>:</strong> Create a simple proof-of-concept that TCP sockets can work on RPG Maker VX.</p>
<p><strong>Table of Contents</strong></p>
<p><a href="#PostPart1"><span style="color:#0000ff;"><strong>Step 1: Use Case</strong></span></a></p>
<p><a href="#PostPart2"><span style="color:#0000ff;"><strong>Step 2: Borrowing Library Code</strong></span></a></p>
<p><a href="#PostPart3"><span style="color:#0000ff;"><strong>Step 3: Initializing &amp; Testing the Connection with NPCs</strong></span></a></p>
<p><a href="#PostPart4"><span style="color:#0000ff;"><strong>Step 4: Taking a Step Back</strong></span></a></p>
<p><a href="#PostPart5"><span style="color:#0000ff;"><strong>Step 5: A Slightly More Impressive Proof-of-concept</strong></span></a></p>
<p><a href="#PostPart6"><span style="color:#0000ff;"><strong>Game Prototype 1: Autosave and an IP NPC</strong></span></a></p>
<p><a href="#PostPart7"><span style="color:#0000ff;"><strong>Game Prototype 2: An Online Community</strong></span></a></p>
<p><a href="#PostPart8"><span style="color:#0000ff;"><strong>Game Prototype 3 &#8211; Chatting with Other Players</strong></span></a></p>
<p><a href="#PostPart9"><span style="color:#0000ff;"><strong>Further Work</strong></span></a></p>
<p><strong><a style="text-decoration:none;color:green;" name="PostPart1">Step 1: Use Case</a></strong></p>
<p>Let&#8217;s start with a brand-new RPG Maker project. Create a starting map, and put down some “land” tiles. Then, add an NPC with the following commands:</p>
<ul>
<li>Message Box: “Opening Socket”</li>
<li>Script:</li>
<pre><code style="color:black;">s<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>TCPSocket<span style="font-weight:bold;color:#000000;">.</span>open<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">'127.0.0.1'</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#800000;">7689</span><span style="font-weight:bold;color:#000000;">)</span>
s<span style="font-weight:bold;color:#000000;">.</span>close<span style="font-weight:bold;color:#000000;">()</span></code></pre>
<li>Message Box: “Success!”</li>
</ul>
<p>Now, start your game and talk to your NPC. You should see the first message box, and then the game will crash.</p>
<div id="attachment_253" class="wp-caption alignnone" style="width: 329px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_first_crash.png"><img class="size-medium wp-image-253" title="post10_first_crash" src="http://lthzelda.files.wordpress.com/2010/04/post10_first_crash.png?w=319&#038;h=225" alt="" width="319" height="225" /></a><p class="wp-caption-text">No &quot;sockets&quot; library means no TCPSocket class, which in turn means that our two-line script will crash horribly.</p></div>
<p>What just happened? Well, first we tried to create a socket. This socket assumed that we have a server running on 127.0.0.1 (which means “this computer”) and that it is bound on port 7689. Since no server has been started, we expect a crash –however, we get the wrong kind of crash. If you look at the message box, you&#8217;ll see that RMVX had trouble finding the “TCPSocket” item. In other words, RPG Maker VX does not ship the default Ruby networking libraries! Oh no!</p>
<p>The thing is, RPG Maker XP <em>also </em>didn&#8217;t ship with networking support. So how does RMX-OS use it? If you&#8217;ve studied programming languages, you know that features such as networking are not considered part of the language itself; they&#8217;re usually linked up directly to the operating system after the language has been created. Doing something like that manually is far too difficult for the average programmer. Fortunately, we might be able to “borrow” the code that Ruby itself uses to connect to sockets.</p>
<p>If you want to follow along, you can download Ruby&#8217;s source (it <em><strong>must </strong></em>be <strong>version 1.8</strong>) from some online source –I recommend the Debian repository, with links below. However, the source really isn&#8217;t necessary, since I&#8217;ll be quoting samples from it when you need them. Moreover, I can&#8217;t seem to <em>find </em>the relevant socket code (although I <em><strong>did </strong></em>find useful Mutex code), so you probably don&#8217;t need to download the source unless you&#8217;re curious. Here are the links:</p>
<p><a href="http://ftp.de.debian.org/debian/pool/main/r/ruby1.8/ruby1.8_1.8.7.249.orig.tar.gz"><span style="color:#0000ff;"><strong>http://ftp.de.debian.org/debian/pool/main/r/ruby1.8/ruby1.8_1.8.7.249.orig.tar.gz</strong></span></a></p>
<p>&#8230;or, more generally, from:</p>
<p><a href="http://packages.debian.org/en/squeeze/ruby1.8"><span style="color:#0000ff;"><strong>http://packages.debian.org/en/squeeze/ruby1.8</strong></span></a></p>
<p>After downloading it, unzip it and remember where you saved the source. The only file we&#8217;ll need is <strong>thread.rb</strong>.</p>
<p><strong><a style="text-decoration:none;color:green;" name="PostPart2">Step 2: Borrowing Library Code</a></strong></p>
<p>One thing you may have noticed if you&#8217;re familiar with ruby is that RGSS (RPG Maker&#8217;s Ruby scripting system) doesn&#8217;t support the “require” primitive. This makes sense –since “require” searches the standard library path,  you might accidentally load Ruby library code which your playtesters likely won&#8217;t have. That said, RPG Maker is still perfectly capable of running native code from DLLs. For example, the following works just fine:</p>
<p><code style="color:black;"> Win32API.new(DLL, 'connect', 'ppl', 'l').call(1, 2, 3)</code></p>
<p>Thus, we might consider chaining together DLL calls to create a kind of “fake” networking library. Eventually, we&#8217;ll probably try to migrate to a so-called “native” library, so that we can gain the benefits of low-level primitives. An example is provided in the win32utils:</p>
<p><a href="http://rubyforge.org/projects/win32utils/"><span style="color:#0000ff;"><strong> http://rubyforge.org/projects/win32utils/</strong></span></a></p>
<p>If you download and scan, say, the win32-nio library source, you&#8217;ll see lots of “require” tags at the top of the main library files. Be aware that you&#8217;ll have to essentially replace these with compatible functionality if you want to use the library.</p>
<p>Therefore, we won&#8217;t use win32-nio just yet. Instead, we&#8217;ll copy the Win32 API that “blizzard” put inside RMX-OS. He claims that it&#8217;s from Ruby&#8217;s 1.8.1 library source, but for the life of me I can&#8217;t find it online. That&#8217;s not really a problem, though, as the <a href="http://www.ruby-lang.org/en/LICENSE.txt"><span style="color:#0000ff;"><strong>Ruby License</strong></span></a> allows verbatim copies of code and distribution in some format.</p>
<p>RMX-OS&#8217;s networking code is, by the way, built on top of DLL calls. Here&#8217;s the code you need to copy:</p>
<p><span style="color:#0000ff;"><strong><a href="http://lthzelda.files.wordpress.com/2010/04/segment1-library-code.odt">Code Segment 1</a></strong></span> — Apologies for the ODT format, but PDF removed newlines and tabs.</p>
<p>In the Script Editor (F11), right-click on “Main” and choose “Insert”. Type “Ruby Library Code” in the “Name” box, and then paste the source code from segment 1 into the edit panel. Choose “ok”, then save your game.</p>
<p>If you run your code now, you&#8217;ll get some vague, disheartening runtime error. So, before you get depressed, delete your test NPC and add the following code directly into the Main script, below Graphics.freeze:</p>
<pre><code style="color:black;">s<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>TCPSocket<span style="font-weight:bold;color:#000000;">.</span>open<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">'127.0.0.1'</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#800000;">7689</span><span style="font-weight:bold;color:#000000;">)</span>
s<span style="font-weight:bold;color:#000000;">.</span>close<span style="font-weight:bold;color:#000000;">()</span></code></pre>
<p>Now, save and run the game. You&#8217;ll get the following error on startup:</p>
<div id="attachment_252" class="wp-caption alignnone" style="width: 295px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_conn_ref_err.png"><img class="size-medium wp-image-252" title="post10_conn_ref_err" src="http://lthzelda.files.wordpress.com/2010/04/post10_conn_ref_err.png?w=285&#038;h=234" alt="" width="285" height="234" /></a><p class="wp-caption-text">This error means the library code loaded, then couldn&#039;t find the server. We are making progress!</p></div>
<p>Now <em><strong>that&#8217;s</strong></em> the kind of error we&#8217;re looking for! Congratulations, the basic structure of the TCP code you added was correct!</p>
<p><strong><a style="text-decoration:none;color:green;" name="PostPart3">Step 3: Initializing &amp; Testing the Connection with NPCs</a></strong></p>
<p>We need to test an actual TCP connection –in addition, we should probably fix that bug where NPCs can&#8217;t seem to trigger our code. These are our next tasks.</p>
<p>If you try to track down the error from the NPC-enabled network code, you&#8217;ll reach the following line:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>check
<span style="color:#808080;">    </span>errno<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Winsock<span style="font-weight:bold;color:#000000;">.</span>WSAGetLastError
<span style="color:#808080;">    </span>raise<span style="color:#808080;"> </span>Errno<span style="font-weight:bold;color:#000000;">.</span>const_get<span style="font-weight:bold;color:#000000;">(</span>Errno<span style="font-weight:bold;color:#000000;">.</span>constants<span style="font-weight:bold;color:#000000;">.</span>detect<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">|</span>c<span style="font-weight:bold;color:#000000;">|</span><span style="color:#808080;"> </span>Errno<span style="font-weight:bold;color:#000000;">.</span>const_get<span style="font-weight:bold;color:#000000;">(</span>c<span style="font-weight:bold;color:#000000;">).</span>new<span style="font-weight:bold;color:#000000;">.</span>errno<span style="font-weight:bold;color:#000000;">==</span><span style="color:#808080;"> </span>errno<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">})</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>The error is located inside that particularly nasy “raise” statement. If you don&#8217;t understand Ruby&#8217;s “block” mechanism, you&#8217;ll probably feel like quitting right here. Instead, try this simple abstraction:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>check
<span style="color:#808080;">    </span>errno<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Winsock<span style="font-weight:bold;color:#000000;">.</span>WSAGetLastError
<span style="color:#808080;">    </span>constName<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Errno<span style="font-weight:bold;color:#000000;">.</span>constants<span style="font-weight:bold;color:#000000;">.</span>detect<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">|</span>c<span style="font-weight:bold;color:#000000;">|</span><span style="color:#808080;"> </span>Errno<span style="font-weight:bold;color:#000000;">.</span>const_get<span style="font-weight:bold;color:#000000;">(</span>c<span style="font-weight:bold;color:#000000;">).</span>new<span style="font-weight:bold;color:#000000;">.</span>errno<span style="font-weight:bold;color:#000000;">==</span><span style="color:#808080;"> </span>errno<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span>raise<span style="color:#808080;"> </span>Errno<span style="font-weight:bold;color:#000000;">.</span>const_get<span style="font-weight:bold;color:#000000;">(</span>constName<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>Run this code again, and the error&#8217;s still on the “raise” line&#8230; but now it&#8217;s superficially easy to understand. The original programmer was trying to look up Win32 error messages by ID, and he didn&#8217;t account for the possibility that a <strong>null</strong> socket might be returned with NO error code being generated in the process. Well, this is easy enough to fix:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>check
<span style="color:#808080;">      </span>errno<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Winsock<span style="font-weight:bold;color:#000000;">.</span>WSAGetLastError
<span style="color:#808080;">      </span>constName<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Errno<span style="font-weight:bold;color:#000000;">.</span>constants<span style="font-weight:bold;color:#000000;">.</span>detect<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{|</span>c<span style="font-weight:bold;color:#000000;">|</span><span style="color:#808080;"> </span>Errno<span style="font-weight:bold;color:#000000;">.</span>const_get<span style="font-weight:bold;color:#000000;">(</span>c<span style="font-weight:bold;color:#000000;">).</span>new<span style="font-weight:bold;color:#000000;">.</span>errno<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">==</span><span style="color:#808080;"> </span>errno<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>constName
<span style="color:#808080;">        </span>raise<span style="color:#808080;"> </span>Errno<span style="font-weight:bold;color:#000000;">.</span>const_get<span style="font-weight:bold;color:#000000;">(</span>constName<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">else</span>
<span style="color:#808080;">        </span>raise<span style="color:#808080;"> </span><span style="color:#7f007f;">"Unknown network error code: </span><span style="font-weight:bold;color:#000000;">#{</span>errno<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">"</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>Now, if you try to trigger a TCP connection from the NPC, you&#8217;ll see your “Unknown network error code” message.</p>
<p>At this point, I should probably mention that using TCPSocket.open() is not technically correct, since it expects to be passed a block of code to execute upon completion. Although that might be ok for simple socket-related tasks (like requesting the current time or weather conditions from a central server), we&#8217;ll need a persistent connection for our game engine. As you might expect, our code will overflow the limits of an NPC&#8217;s script command. So, change the NPC&#8217;s script code to read:</p>
<p><code style="color:black;">tcptest()</code></p>
<p>&#8230;and add the following to the &#8220;Main&#8221; module, directly above the first &#8220;begin&#8221; statement:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">tcptest</span>
<span style="color:#808080;">    </span><span style="color:#007f00;">#Createa a socket</span>
<span style="color:#808080;">    </span>s<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>TCPSocket<span style="font-weight:bold;color:#000000;">.</span>new<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">'127.0.0.1'</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#800000;">7689</span><span style="font-weight:bold;color:#000000;">)</span>

<span style="color:#808080;">    </span><span style="color:#007f00;">#Send a test message</span>
<span style="color:#808080;">    </span>s<span style="font-weight:bold;color:#000000;">.</span>send<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"Testing...\n"</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#007f00;">#Receive a result from the server</span>
<span style="color:#808080;">    </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">''</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">while</span>
<span style="color:#808080;">      </span>buffer<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>s<span style="font-weight:bold;color:#000000;">.</span>recv<span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">1024</span><span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;">    </span><span style="color:#007f00;">#Read UP TO 1024 bytes</span>
<span style="color:#808080;">      </span>buffer<span style="font-weight:bold;color:#000000;">.</span>gsub!<span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">0.chr</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#7f007f;">''</span><span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="color:#007f00;">#Remove null bytes</span>
<span style="color:#808080;">      </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+=</span><span style="color:#808080;"> </span>buffer<span style="color:#808080;">            </span><span style="color:#007f00;">#Append received data</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">break</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>buffer<span style="font-weight:bold;color:#000000;">.</span>count<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"\n"</span><span style="font-weight:bold;color:#000000;">)&gt;</span><span style="color:#800000;">0</span><span style="color:#808080;">   </span><span style="color:#007f00;">#Stop if we've reached the newline</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">    </span><span style="color:#007f00;">#Done; close the socket, print our message</span>
<span style="color:#808080;">    </span>s<span style="font-weight:bold;color:#000000;">.</span>close<span style="font-weight:bold;color:#000000;">()</span>
<span style="color:#808080;">    </span>print<span style="color:#808080;"> </span><span style="color:#7f007f;">"Received: </span><span style="font-weight:bold;color:#000000;">#{</span>msg<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">"</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>Our code is fairly simple; we use “new” instead of “open”, and then rely on “send” and “recv” to send and receive our data. One problem with “recv” is that it won&#8217;t wait until the server has sent the entire message, so we have to chain together all of the bits and pieces of the message as they arrive. On the upside, one of the guarantees of TCP is that we&#8217;ll never receive messages out-of-order, so that&#8217;s one less potential headache.</p>
<p>Now all we need is the server. I find Ruby a bit distasteful for client/server code, so let&#8217;s try writing one in Java. One issue with Java is that compiling and running it can be a pain. Rather than give you a full tutorial on <a href="http://www.eclipse.org/"><span style="color:#0000ff;"><strong>Eclipse</strong></span></a> or javac, I&#8217;m going to ask you to download and install <a href="http://www.textpad.com/"><span style="color:#0000ff;"><strong>TextPad</strong></span></a>.</p>
<p><strong>Edit: </strong>Some users reported needing to download the JDK, too. Open a command prompt and type <strong>javac -version</strong>. If you get an error message, you&#8217;ll need to <a href="http://java.sun.com/javase/downloads/widget/jdk6.jsp"><strong><span style="color:#0000ff;">download the JDK</span></strong></a>. If all else fails, see the &#8220;source code&#8221; section for compiled versions of the server code.</p>
<p>Now, create a new file, and save it as <strong>SimpleServer.java</strong>. The name <em><strong>must </strong></em>be spelled exactly this way; such a naming convention is a feature of Java. Inside the file, add the following code:</p>
<pre><code style="color:black;"><span style="font-weight:bold;color:#00007f;">import</span><span style="color:#808080;"> </span>java<span style="font-weight:bold;color:#000000;">.</span>io<span style="font-weight:bold;color:#000000;">.*;</span>
<span style="font-weight:bold;color:#00007f;">import</span><span style="color:#808080;"> </span>java<span style="font-weight:bold;color:#000000;">.</span>net<span style="font-weight:bold;color:#000000;">.*;</span>

<span style="font-weight:bold;color:#00007f;">class</span><span style="color:#808080;"> </span>SimpleServer<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">static</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>main<span style="font-weight:bold;color:#000000;">(</span>String<span style="color:#808080;"> </span>argv<span style="font-weight:bold;color:#000000;">[])</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">throws</span><span style="color:#808080;"> </span>Exception<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">    </span>String<span style="color:#808080;"> </span>clientSentence<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span>String<span style="color:#808080;"> </span>capitalizedSentence<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span>ServerSocket<span style="color:#808080;"> </span>welcomeSocket<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>ServerSocket<span style="font-weight:bold;color:#000000;">(</span><span style="color:#007f7f;">7689</span><span style="font-weight:bold;color:#000000;">);</span>

<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">;</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">;</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"Waiting for connection..."</span><span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span>Socket<span style="color:#808080;"> </span>connectionSocket<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>welcomeSocket<span style="font-weight:bold;color:#000000;">.</span>accept<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">      </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"  &gt;Socket connected"</span><span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">
      </span>BufferedReader<span style="color:#808080;"> </span>inFromClient<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>BufferedReader<span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>InputStreamReader<span style="font-weight:bold;color:#000000;">(</span>connectionSocket<span style="font-weight:bold;color:#000000;">.</span>getInputStream<span style="font-weight:bold;color:#000000;">()));</span>
<span style="color:#808080;">      </span>DataOutputStream<span style="color:#808080;"> </span>outToClient<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>DataOutputStream<span style="font-weight:bold;color:#000000;">(</span>connectionSocket<span style="font-weight:bold;color:#000000;">.</span>getOutputStream<span style="font-weight:bold;color:#000000;">());</span>
<span style="color:#808080;">      </span>clientSentence<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>inFromClient<span style="font-weight:bold;color:#000000;">.</span>readLine<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">
      </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"  &gt;Received: "</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>clientSentence<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span>capitalizedSentence<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>clientSentence<span style="font-weight:bold;color:#000000;">.</span>toUpperCase<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="color:#7f007f;">'\n'</span><span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">      </span>outToClient<span style="font-weight:bold;color:#000000;">.</span>writeBytes<span style="font-weight:bold;color:#000000;">(</span>capitalizedSentence<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"  &gt;Replied: "</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>capitalizedSentence<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="font-weight:bold;color:#000000;">}</span></code></pre>
<p>Pretty simple? We&#8217;ve ignored error checking in this code, so it&#8217;ll be fairly easy to crash the server. But for a quick demo, it&#8217;ll do. The server reads a sentence from the client, and capitalizes the alphabetic characters. It then returns this uppercase version of the sentence. Since we send “Testing&#8230;” to the server, we expect the result to be “TESTING&#8230;”.</p>
<p>To compile the server code, choose “Tools-&gt;External Tools-&gt;Compile Java” (or Ctrl+1).</p>
<div id="attachment_254" class="wp-caption alignnone" style="width: 290px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_javatextpad.png"><img class="size-medium wp-image-254" title="post10_javatextpad" src="http://lthzelda.files.wordpress.com/2010/04/post10_javatextpad.png?w=280&#038;h=232" alt="" width="280" height="232" /></a><p class="wp-caption-text">Compiling Java code in TextPad</p></div>
<p>If your code contained no errors (and it shouldn&#8217;t if you&#8217;re copying and pasting) then you&#8217;ll see a message in the output window that reads “Tool completed successfully”. Now, choose “Tools-&gt;External Tools-&gt;Run Java Application”. At this point, a command window will appear bearing the message “Waiting for connection&#8230;”</p>
<div id="attachment_280" class="wp-caption alignnone" style="width: 271px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_server_ready.png"><img class="size-medium wp-image-280" title="post10_server_ready" src="http://lthzelda.files.wordpress.com/2010/04/post10_server_ready.png?w=261&#038;h=150" alt="" width="261" height="150" /></a><p class="wp-caption-text">If you see this text, then your server has been successfully bound to port 7689.</p></div>
<p>This means that our server is ready for the game client to connect to it. Run the game, then talk to the NPC. You&#8217;ll see a popup dialog with the response from the server.</p>
<div id="attachment_281" class="wp-caption alignnone" style="width: 282px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_server_works.png"><img class="size-medium wp-image-281" title="post10_server_works" src="http://lthzelda.files.wordpress.com/2010/04/post10_server_works.png?w=272&#038;h=220" alt="" width="272" height="220" /></a><p class="wp-caption-text">Our RPG has successfully communicated with the server, sending it a message and receiving one back in return.</p></div>
<p>The server window will also have a few more messages:</p>
<div id="attachment_279" class="wp-caption alignnone" style="width: 282px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_server_log.png"><img class="size-medium wp-image-279" title="post10_server_log" src="http://lthzelda.files.wordpress.com/2010/04/post10_server_log.png?w=272&#038;h=149" alt="" width="272" height="149" /></a><p class="wp-caption-text">Our server log proves that the communication was real, and also that Java and ruby can &quot;speak the same language&quot; using sockets.</p></div>
<p>Note that, since we closed the connection, the server is now waiting for another connection to be opened. We could talk to the NPC again, or simply close and re-open the game, then talk to the NPC again. Eventually, we will require each client to hold on to a connection from the server, but for now this proves the concept: networked RPGs in RPG Maker VX should work just fine. Press Ctrl+C to close the window; you might then have to type &#8220;Y&#8221; and press Enter to confirm that you want the server to halt.<br />
<strong> </strong></p>
<p><strong><a style="text-decoration:none;color:green;" name="PostPart4">Step 4: Taking a Step Back</a></strong></p>
<p>At this point, it&#8217;s worth pausing for a second to consider what we&#8217;ve actually accomplished. There&#8217;s a lot of “glue code” (like reading lines of text from ruby) that hides what&#8217;s actually going on:</p>
<ul>
<li>We&#8217;ve created a server that can “receive” connections on port 7689, and a client that can request a “connection” on this port.</li>
<li>Once connected, a client and a server can send and receive a sequence of characters.</li>
</ul>
<p>That&#8217;s all there is to it. Adding multiple clients, some kind of synchronization, and partitioning our data into “messages” or “game events” are just additional details on top of what the tcp client actually is. For example, instead of sending strings of messages, we could send pairs of NPC x/y co-ordinates. In that way, we could treat “heroes” in separate RPGs as “npcs” in your RPG world. We could send “tiles”, and allow users to build their own houses (as maps) which they can allow their friends to visit. We can send custom avatar pictures for each player, or even co-ordinate some kind of battle system. All of these things can be accomplished simply by sending letters and numbers over a TCP connection.</p>
<p><strong><a style="text-decoration:none;color:green;" name="PostPart5">Step 5: A Slightly More Impressive Proof-of-concept</a></strong></p>
<p>Our “borrowed” Ruby source code is about 500 lines in total. This is only about 8% of the total RMX-OS code, which includes things like <strong>Scenes </strong>for connecting to the network and a password system to help protect users&#8217; passwords and privacy. My point is, making anything interesting is going to be a huge undertaking. On the other hand, a simple message box usually isn&#8217;t enough to prove to your boss that you&#8217;ve accomplished a huge feat like networking a game engine that doesn&#8217;t normally expect to be multiplayer. What, then, might a nice, simple prototype look like?</p>
<ul>
<li>We don&#8217;t want to play around with <strong>Scene </strong>overloading. So let&#8217;s make an NPC that basically allows us to connect to a network, and manage our network configurations.</li>
<li>When the game begins, the player can choose one of four starting heroes. This information is transmitted over the network.</li>
<li>At this point, we should create NPCs for each of the other users online. These will just wander randomly for now; they won&#8217;t reflect the actual position of the other users.</li>
<li>The hero can talk to these NPCs to receive “messages” that they have sent (like a chat). Only the most recent message is shown.</li>
<li>When an NPC gets a new message to display, we can show a “balloon” animation above him –an exclamation mark or something similar.</li>
<li>To send a message, the hero can talk to another NPC (like the connection NPC). We might use the hero name dialog, or we might capture key presses. In the worst case, we&#8217;ll just let the user select some pre-defined messages from a list.</li>
</ul>
<p>There&#8217;s a lot of bullets (e.g., a lot of things to show off) but individually, each is not terribly difficult to accomplish. Let&#8217;s get started!</p>
<p><em><strong><span style="color:#ff0000;">VERY  IMPORTANT NOTE:</span> </strong></em>Whenever you change some of your game&#8217;s code (scripts), you should re-test using a <strong>new</strong> game. If not, you risk loading old code from an old save file (it happened once to me, while testing this blog entry) and it is frustrating to track down an error like this. In my case, the <strong>initialize</strong> method for my <strong>Game_Map</strong> class was not re-called upon loading an existing save file, and I couldn&#8217;t figure out why some class variables didn&#8217;t exist anymore.</p>
<p><strong><a style="text-decoration:none;color:green;" name="PostPart6">Game Prototype 1: Autosave and an IP NPC</a></strong></p>
<p>Our first prototype will have no networking capability at all. We&#8217;ll need two maps; one for the player to select an Avatar upon starting a “New Game”, and the other for normal play. Create these two maps and call them “Player House” and “Character Select”. Make them both small (20 x 15 or so) and go to the<strong> Character Select</strong> map. Give it a fancy layout and set the hero&#8217;s starting position to be somewhere on the map.</p>
<div id="attachment_265" class="wp-caption alignnone" style="width: 297px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_starting_map.png"><img class="size-medium wp-image-265" title="post10_prot1_starting_map" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_starting_map.png?w=287&#038;h=184" alt="" width="287" height="184" /></a><p class="wp-caption-text">Our spartan starting map.</p></div>
<p>Now, add a few NPCs (five would be good), each with the graphics of the first five heroes in the party. If you don&#8217;t like the default hero pictures, you should go into the database editor (F9) and change them. Just make sure they match the pictures of the NPCs you just added. While you&#8217;re in the database editor, you might want to change the <strong>Initial Party</strong> (in the <strong>System </strong>tab) to include only <strong>hero 6</strong>, and change <strong>hero 6</strong>&#8216;s walkabout to be something more mysterious. Name him <strong>SELECT </strong>to avoid confusion.</p>
<div id="attachment_258" class="wp-caption alignnone" style="width: 256px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_heroes_added.png"><img class="size-medium wp-image-258" title="post10_prot1_heroes_added" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_heroes_added.png?w=246&#038;h=157" alt="" width="246" height="157" /></a><p class="wp-caption-text">Five possible Avatars on our starting map.</p></div>
<p>If that was all too much for you, you might consider reading through a few RPG Maker tutorials –this blog post would likely double in size if I tailored it to complete beginners. (If someone&#8217;s willing to do a voiceover for me, I&#8217;ll put up a video walkthrough on Youtube.)</p>
<p>Open up the left-most NPC in the Event Editor (double-click) and add the following on page 1:</p>
<div id="attachment_263" class="wp-caption alignnone" style="width: 395px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_selectnpc.png"><img class="size-medium wp-image-263" title="post10_prot1_selectnpc" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_selectnpc.png?w=385&#038;h=310" alt="" width="385" height="310" /></a><p class="wp-caption-text">Talking to an NPC activates this event, which asks the user if she wants this avatar.</p></div>
<p>To summarize that code briefly:</p>
<ul>
<li>Show a text box asking if the player wants this hero.</li>
<li>Have a “choice” command (Yes/No). We only care if the user picks “Yes”</li>
<li>If so, set variable 1 (which we call <strong>Avatar ID</strong>) to be <span style="color:#ff0000;"><strong>1</strong></span>.</li>
<li>We then add the <span style="color:#ff0000;"><strong>first</strong></span> hero (“Ralph”) to the party.</li>
<li>We remove the <strong>SELECT</strong> hero.</li>
<li>We transport to a random point on the <strong>Player House</strong> map.</li>
<li>We then “auto-save” using the following script:</li>
<pre><code style="color:black;">Scene_File.auto_save($game_variables[2])</code></pre>
</ul>
<p>Now, before we talk about auto-saving, copy and paste the event code from NPC 1 to each of the other 4 NPCs. When you paste the events, make sure to change the text in red to reflect avatar<strong> </strong><span style="color:#ff0000;"><strong>2</strong></span>, <span style="color:#ff0000;"><strong>3</strong></span>, etc. Each player should introduce him or herself, ask the player to choose him/her, and then save his/her details into variable 1 and create a party with only him/her in it. Isn&#8217;t gender neutral language fun?</p>
<p>Let&#8217;s talk about the auto-save. You can probably guess that “auto-save” is (or will be) a static method in the <strong>Scene_File</strong> class, and that it will take a save slot <strong>ID </strong>(which we will store in <strong>variable 2</strong>. Open the script editor (F11) and browse to Scene_File. Add the following directly underneath <strong>Scene File &lt; Scene Base</strong>:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#Save to a slot directly.</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#Indexed from 1, not 0.</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>auto_save<span style="font-weight:bold;color:#000000;">(</span>file_index<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span>fileName<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;font-size:9pt;">"Save</span><span style="font-weight:bold;color:#000000;">#{</span>file_index<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;font-size:9pt;">.rvdata"</span>
<span style="color:#808080;">    </span>file<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>File<span style="font-weight:bold;color:#000000;">.</span>open<span style="font-weight:bold;color:#000000;">(</span>fileName<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#7f007f;font-size:9pt;">"wb"</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span>Scene_File<span style="font-weight:bold;color:#000000;">.</span>write_save_data<span style="font-weight:bold;color:#000000;">(</span>file<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span>file<span style="font-weight:bold;color:#000000;">.</span>close
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>We copied most of this code from the <strong>do_save</strong> method, making sure to construct the right file name. By naming our code as <strong>self</strong>.auto_save, we make the method static –the user code doesn&#8217;t need a (<strong>new</strong>) object to use the function. Unfortunately, this requires that  <strong>write_save_data</strong> also be static. Find the following line in <strong>Scene_File</strong>:</p>
<pre><code style="color:black;"><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">write_save_data</span><span style="font-weight:bold;color:#000000;">(</span>file<span style="font-weight:bold;color:#000000;">)</span></code></pre>
<p>&#8230;and change it to</p>
<pre><code style="color:black;"><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><em><strong><span style="color:#007f7f;">self</span></strong></em><span style="font-weight:bold;color:#000000;">.</span>write_save_data<span style="font-weight:bold;color:#000000;">(</span>file<span style="font-weight:bold;color:#000000;">)</span></code></pre>
<p>However, this will break <em>normal </em>saving, which we probably don&#8217;t want. Find the following function in <strong>Scene_File</strong>:</p>
<pre><code style="color:black;"><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">do_save</span>
  <span style="color:#808080;"> </span>file<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>File<span style="font-weight:bold;color:#000000;">.</span>open<span style="font-weight:bold;color:#000000;">(</span><span style="color:#b00080;">@savefile_windows</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#b00080;">@index</span><span style="font-weight:bold;color:#000000;">].</span>filename<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#7f007f;font-size:9pt;">"wb"</span><span style="font-weight:bold;color:#000000;">)</span>
  <span style="color:#808080;"> </span>write_save_data<span style="font-weight:bold;color:#000000;">(</span>file<span style="font-weight:bold;color:#000000;">)</span>
  <span style="color:#808080;"> </span>file<span style="font-weight:bold;color:#000000;">.</span>close
  <span style="color:#808080;"> </span>return_scene
<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>&#8230;and change it to:</p>
<pre><code style="color:black;"><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">do_save</span>
  <span style="color:#808080;"> </span>file<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>File<span style="font-weight:bold;color:#000000;">.</span>open<span style="font-weight:bold;color:#000000;">(</span><span style="color:#b00080;">@savefile_windows</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#b00080;">@index</span><span style="font-weight:bold;color:#000000;">].</span>filename<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#7f007f;font-size:9pt;">"wb"</span><span style="font-weight:bold;color:#000000;">)</span>
  <span style="color:#808080;"> </span><em><strong>Scene_File</strong></em><span style="font-weight:bold;color:#000000;">.</span>write_save_data<span style="font-weight:bold;color:#000000;">(</span>file<span style="font-weight:bold;color:#000000;">)</span>
  <span style="color:#808080;"> </span>file<span style="font-weight:bold;color:#000000;">.</span>close
  <span style="color:#808080;"> </span>return_scene
<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>This way,<strong> do_save</strong> will still work properly (by calling the now-static function). There are other ways to accomplish this, but this is the easiest to describe.</p>
<p>One tiny problem remains: how do we save the preferred autosave slot into <strong>variable 2</strong>? I see three possibilities:</p>
<ul>
<li>Just pick a slot (e.g., &#8220;the first save file&#8221;) and use that. This is <strong>too hot</strong> –it forces an arbitrary choice on the player.</li>
<li>Give the player a <strong>choice </strong>box with options “1,2,3,4”. This is<strong> too cold</strong> –it&#8217;s a bit impersonal for players used to the nice save dialog of RPG Maker.</li>
<li>Force the player to save the game once, and use that value. This is <strong>just right</strong> –it&#8217;s natural to the player, and shouldn&#8217;t be too hard to figure out from our end.</li>
</ul>
<p>Needless to say, we&#8217;re doing option 3. Create a new event with no graphic in the top-left corner of the map and give it two pages. The second page should have the “Switch” box checked under “Conditions”, and have “Switch 1” selected. (We call this switch <strong>Chose Save Slot</strong>.) The first page should have its trigger set to “Autorun”, and have the following event code:</p>
<div id="attachment_264" class="wp-caption alignnone" style="width: 353px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_setupautosave.png"><img class="size-medium wp-image-264" title="post10_prot1_setupautosave" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_setupautosave.png?w=343&#038;h=276" alt="" width="343" height="276" /></a><p class="wp-caption-text">The code for our auto-save enforcing NPC.</p></div>
<p>In other words, we first tell the user to select an auto-save slot. Then, we show them the save menu. Now we need to check if the user canceled the menu. We do this by setting variable 3 (called <strong>TMP Save Count</strong>) to be equal to “Save Count” (listed under “Other” in the variables dialog). We then do a simple conditional branch: if this variable is greater than zero, we continue. The first thing we now do is execute a nifty script:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#Set var[2] to the save slot</span>
<span style="color:#808080;">  </span>slot<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_temp</span><span style="font-weight:bold;color:#000000;">.</span>last_file_index<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="color:#800000;">1</span>
<span style="color:#808080;">  </span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">2</span><span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>slot</code></pre>
<p>The variable<strong> last_file_index</strong> is already part of the game engine. It stores the id of the last slot saved to, starting from zero. (Since save slots are actually numbered from 1, we increment this value.) The default value for <strong>last_file_index</strong> is zero, by the way, so we can&#8217;t just check this to determine if the user canceled or saved.</p>
<p>Moving on, we then set <strong>switch 1</strong> to <strong>ON</strong>. Next, we set the names of heroes 7 and 8 to <strong>127.0.0.1:7689</strong>. This is not very important right now; just add the lines and we&#8217;ll get back to them later. Finally, we perform our “classic auto-save”</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#Save the game to slow (ID-1)</span>
<span style="color:#808080;">  </span>Scene_File<span style="font-weight:bold;color:#000000;">.</span>auto_save<span style="font-weight:bold;color:#000000;">(</span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">2</span><span style="font-weight:bold;color:#000000;">])</span></code></pre>
<p>You should memorize this code fragment; we&#8217;ll be using it a lot.</p>
<p>At this point, you can run the game, and you will be prompted to save. Following that, you can choose a hero and then walk around the <strong>Player House</strong> map. Not too bad for a quick-and-dirty auto-save, eh? In fact, if you play around with quitting and reloading games, you&#8217;ll find that our code is actually pretty robust; cancel or close the program whenever you want and everything should still work fine when you reload it.</p>
<div id="attachment_266" class="wp-caption alignnone" style="width: 278px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_testautosave.png"><img class="size-medium wp-image-266" title="post10_prot1_testautosave" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_testautosave.png?w=268&#038;h=217" alt="" width="268" height="217" /></a><p class="wp-caption-text">Our auto-save dialog performs impressively.</p></div>
<p>Go to the <strong>Player House</strong> map and create a nice, homely setting. Add some ambient NPCs if you want; just make sure there&#8217;s a scholarly-looking NPC somewhere near the middle of the map. We&#8217;ll use him for connecting to the server. Here&#8217;s just one possible setup:</p>
<div id="attachment_259" class="wp-caption alignnone" style="width: 299px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_home_map.png"><img class="size-medium wp-image-259" title="post10_prot1_home_map" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_home_map.png?w=289&#038;h=202" alt="" width="289" height="202" /></a><p class="wp-caption-text">Only the primary NPC matters, but feel free to make this map as picturesque as you like.</p></div>
<p>This NPC will have a whole lot of functionality wrapped up inside his persona. To make the code more manageable, we&#8217;ll put different functions into different common events. The core code for the map NPC looks like this:</p>
<div id="attachment_260" class="wp-caption alignnone" style="width: 386px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_npccore.png"><img class="size-medium wp-image-260" title="post10_prot1_npccore" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_npccore.png?w=376&#038;h=304" alt="" width="376" height="304" /></a><p class="wp-caption-text">The main code of our &quot;Connect&quot; NPC.</p></div>
<p>To summarize:</p>
<ul>
<li>This NPC can either introduce himself or call the “Connect to a server” <strong>Common Event</strong>, which has the ID of 1. The rest is just fluff.</li>
</ul>
<p>Open the database editor (F9) and browse to the <strong>Actors </strong>tab. Name actor 7 <strong>SAVED_SERVER_1</strong> and actor 8 <strong>SAVED_SERVER_2</strong>. Then browse to the <strong>Common Events</strong> tab. Name common event 1 <strong>&#8220;Connect to a server&#8221; menu</strong>. Name common event 2 <strong>Prompt for server address</strong>. Name common event 3 <strong>Prompt to Save Server</strong>. Now, for common event 1, add the following code:</p>
<div id="attachment_255" class="wp-caption alignnone" style="width: 374px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_ce1.png"><img class="size-medium wp-image-255" title="post10_prot1_ce1" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_ce1.png?w=364&#038;h=305" alt="" width="364" height="305" /></a><p class="wp-caption-text">CE 1 handles connecting to a server. It is currently incomplete.</p></div>
<p>This event is quite simple:</p>
<ul>
<li>First, it asks the user to choose a server. The first two options are the names of the <strong>SERVER </strong>characters that we just created. At present, nothing happens when these are selected. The third option allows us to add a new server. It calls the following two common events in sucession.</li>
</ul>
<p>The second common event is also quite simple, if a bit repetitive:</p>
<div id="attachment_256" class="wp-caption alignnone" style="width: 394px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_ce2.png"><img class="size-medium wp-image-256" title="post10_prot1_ce2" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_ce2.png?w=384&#038;h=367" alt="" width="384" height="367" /></a><p class="wp-caption-text">CE 2 allows us to construct new IP addresses. It&#039;s just a little cumbersome.</p></div>
<p>It performs the following routine five times:</p>
<ul>
<li>Tell the user the name of hero <strong>SELECTION</strong>, then ask for a number. Store this number in variable 4 (<strong>TMP server part</strong>)</li>
<li>Append this number to the name of the <strong>SELECTION </strong>hero using the following script:
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#Set actor's name</span>
<span style="color:#808080;">  </span>actor<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_actors</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">6</span><span style="font-weight:bold;color:#000000;">]</span>
<span style="color:#808080;">  </span>actor<span style="font-weight:bold;color:#000000;">.</span>name<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;font-size:9pt;">"</span><span style="font-weight:bold;color:#000000;">#{</span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">4</span><span style="font-weight:bold;color:#000000;">]}</span><span style="color:#7f007f;font-size:9pt;">."</span></code></pre>
<ul>
<li>&#8230;note, of course, that the &#8220;.&#8221; changes to a &#8220;:&#8221; for entry 4, and &#8220;&#8221; (nothing) for entry 5.</li>
</ul>
</li>
</ul>
<p>The third common event simply checks if this is what the user wants:</p>
<div id="attachment_257" class="wp-caption alignnone" style="width: 375px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_ce3.png"><img class="size-medium wp-image-257" title="post10_prot1_ce3" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_ce3.png?w=365&#038;h=306" alt="" width="365" height="306" /></a><p class="wp-caption-text">CE 3 just confirms the user&#039;s entry, saves it, and resets the SELECTION npc&#039;s name.</p></div>
<p>It saves, e.g., actor 7 by using the following script:</p>
<pre><code style="color:black;"><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">#Finalize actor's name</span>
<span style="color:#808080;"> </span><span style="color:#800080;">$game_actors</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">7</span><span style="font-weight:bold;color:#000000;">].</span>name<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_actors</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">6</span><span style="font-weight:bold;color:#000000;">].</span>name</code></pre>
<p>Of course, we reset the <strong>SELECT </strong>hero&#8217;s name to avoid confusion later. We then wrap it all up with an auto-save. And that&#8217;s it! We now have a simple way to enter server addresses without requiring any fancy interface or custom save files. Here&#8217;s a screenshot of our system in action:</p>
<div id="attachment_261" class="wp-caption alignnone" style="width: 273px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_partialip.png"><img class="size-medium wp-image-261" title="post10_prot1_partialip" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_partialip.png?w=263&#038;h=213" alt="" width="263" height="213" /></a><p class="wp-caption-text">The orange text makes it look at least ten times more professional.</p></div>
<p>Once the selection has been saved, it shows up on our options list:</p>
<div id="attachment_262" class="wp-caption alignnone" style="width: 266px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_savedip.png"><img class="size-medium wp-image-262" title="post10_prot1_savedip" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_savedip.png?w=256&#038;h=207" alt="" width="256" height="207" /></a><p class="wp-caption-text">The beauty of using an Actor&#039;s name to save the IP address is that you can use it in a Message Box without any fancy tricks.</p></div>
<p>It&#8217;s nearly time to move on to our second prototype (which will introduce network elements). Before we get too far ahead, I&#8217;d like to highlight some of the merits of our approach:</p>
<ul>
<li>We relied for the most part on<strong> local scripts</strong>, requiring only a single change to the game&#8217;s source code. In our defense, the function <strong>write_save_data</strong> should have been static anyway, and could have been fudged if we were so inclined to create a dummy object.</li>
<li>By using several <strong>Common Events</strong>, we avoided the RPG Maker-exclusive temptation to create one messy NPC with all our code. In fact, nearly all events had single-screen pages of Event Commands.</li>
<li>We used “special heroes” to store our IP addresses. This allowed us to stick with event commands like “Show Choice” instead of requiring custom Scripts for everything.</li>
<li>By and large, we used mostly RPG Maker constructs, relying on scripts only for tiny globs of “glue code” where the interpreter fell short. Most intermediate RMVX users could probably figure out what our code does, and how to improve it.</li>
</ul>
<p>Enough resting on our laurels; it&#8217;s time to notch up the interest level of our audience.</p>
<p><strong><a style="text-decoration:none;color:green;" name="PostPart7">Game Prototype 2: An Online Community</a></strong></p>
<p>We strive for incremental improvements, so let&#8217;s try adding only the most basic of network functionality:</p>
<ul>
<li>When a user <strong>Connects</strong>, we&#8217;ll add an (arbitrary) NPC to the player&#8217;s home map.</li>
<li>When a user <strong>Disconnects </strong>or closes the game, we&#8217;ll remove this NPC.</li>
</ul>
<p>This will require a lot more foresight than you might expect. First, we need to decide how the client should handle messages. After all, we don&#8217;t want our game engine to hang just because the network goes down. Following that, we&#8217;ll need a simple <strong>message format</strong> that is simple to expand with new data types. Finally, we&#8217;ll need a <strong>messaging protocol</strong>: how often should we send updates to users? For now, we&#8217;ll just assume “always send every update”, since we&#8217;re not tracking anything expensive like a user&#8217;s X/Y co-ordinates. For bigger games, the messaging protocol is the most important part of the network design. If your game&#8217;s lagging, try reading a few papers on <a href="http://gram.cs.mcgill.ca/papers/boulanger-06-comparing.pdf"><strong><span style="color:#0000ff;">interest management</span></strong></a> (PDF link) in online games.</p>
<p>First, let&#8217;s talk about <strong>threading</strong>. Like most modern high-level languages, Ruby runs inside a<strong> virtual machine</strong>, which itself is a single process in the Windows operating system. All ruby-related code in your game must therefore run in sequence. This includes <em>all </em>parallel or autostart events, common events, NPC interactions, and scripts. Unfortunately, this makes it very difficult to add networking. Let&#8217;s say that you check for messages from the server before you service all parallel process events. If your game has a lot of these events running at once, the network buffer might overflow, and you&#8217;ll lose messages. (Very Bad.) What we really want is a way of telling Ruby to check for network messages “every so often”. That&#8217;s exactly what <strong>threads </strong>were designed to do.</p>
<p>Consider the following Ruby code:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#Code our thread will execute</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">network_thread</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">while</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">true</span>
<span style="color:#808080;">      </span>read_server_messages<span style="font-weight:bold;color:#000000;">()</span>
<span style="color:#808080;">      </span>send_waiting_messages_to_server<span style="font-weight:bold;color:#000000;">()</span>
<span style="color:#808080;">      </span>sleep<span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">#Avoid spinning too fast</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>

<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#Actually make a thread</span>
<span style="color:#808080;">  </span>t1<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Thread<span style="font-weight:bold;color:#000000;">.</span>new<span style="font-weight:bold;color:#000000;">{</span>network_thread<span style="font-weight:bold;color:#000000;">()}</span></code></pre>
<p>Conceptually, the line with <strong>Thread.new</strong> tells Ruby&#8217;s virtual machine to make the <strong>network_thread()</strong> function run <em>once </em>inside a new thread. This thread will alternate with the main (RPG Maker) thread in the virtual machine. According to Ruby&#8217;s time-slicing policy, each thread will run for 10ms before the other thread gets a turn to run. Inside <strong>network_thread</strong>, we call a function which reads all messages that the server has sent to us. Note that we do not process these messages yet; we&#8217;ll do that in the main game thread. Instead, we simply get them out of the network buffer and into the game engine. Following that, we send any waiting messages to the server. Again, these messages are generated by the game engine; we don&#8217;t really care how they&#8217;re made. Then, we perform a call to “sleep”, which forces the current thread to suspend. That way, if we only used 2ms of our time slice, the main game engine doesn&#8217;t have to wait 8ms while we do nothing useful.</p>
<p>This is only one way of doing things. We might also have put <strong>read_server_messages</strong> and <strong>send_waiting_messages_to_server</strong> into their own separate threads.</p>
<p>Now, let&#8217;s talk synchronization. Where does<strong> read_server_messages</strong> save the messages it reads? Presumably, we&#8217;ll have an array to store them:</p>
<pre><code style="color:black;"> read_messages<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">[]</span></code></pre>
<p>The network thread can then put messages into the back of this array, and the game engine can read messages from the front. The problem is, what happens if both try to act on the array at the same time? The answer: something Very Bad. To avoid this, we should <strong>synchronize </strong>access to this array. For example, the game engine might contain code like the following:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span>GameMessage<span style="color:#808080;"> </span>nextMessage<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span>
<span style="color:#808080;">  </span><span style="color:#b00080;">@lock</span><span style="font-weight:bold;color:#000000;">.</span>synchronize<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span>
<span style="color:#808080;">    </span>nextMessage<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>read_messages<span style="font-weight:bold;color:#000000;">.</span>shift<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">unless</span><span style="color:#808080;"> </span>read_messages<span style="font-weight:bold;color:#000000;">.</span>empty?
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>nextMessage
<span style="color:#808080;">    </span><span style="color:#007f00;font-size:9pt;">#....process nextMessage</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>The @lock variable might be created with a call to:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#b00080;">@lock</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Mutex<span style="font-weight:bold;color:#000000;">.</span>new</code></pre>
<p>It ensures that <em>all </em>the code inside the locked block executes before any other locked code. To avoid unnecessary slowdown, it is a good idea to keep the code inside a lock block as simple as possible –note that we store the next message in <strong>nextMessage</strong>, rather than processing it inside the locked section.</p>
<p>There&#8217;s just one problem: Mutex.new requires the &#8216;thread&#8217; library. And I mean <strong>require</strong>s; that is, we don&#8217;t have access to it in RPG Maker code. (Thankfully, we <em>do </em>have access to <strong>thread</strong>). We can&#8217;t use the equivalent “monitor” class; it&#8217;s also required. Fortunately, there&#8217;s an easier solution. Remember the <strong>ruby 1.8 source code</strong> we downloaded earlier? Go to that directory, and then browse to the <strong>lib </strong>directory. You&#8217;ll see the <strong>thread.rb</strong> file which contains mutexes. Copy and paste the source code into your <strong>Ruby Library Code</strong> module (F11) at the very top. Segment 2 contains this code, minus most comments:</p>
<p><a href="http://lthzelda.files.wordpress.com/2010/04/segment2-mutex-code.odt">Code Segment 2</a> &#8211; Ruby code.</p>
<p>And that&#8217;s all we need to do to enable mutex creation:</p>
<div id="attachment_270" class="wp-caption alignnone" style="width: 289px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_mutextest.png"><img class="size-medium wp-image-270" title="post10_prot2_mutextest" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_mutextest.png?w=279&#038;h=231" alt="" width="279" height="231" /></a><p class="wp-caption-text">The Mutex object was created properly. (Sample source code not included.)</p></div>
<p>We nearly hit a dead-end, but synchronization works. Bullet dodged; that could have killed the entire project. (Although not entirely: RMX-OS doesn&#8217;t use threads and achieves reasonable performance.)</p>
<p>All drama aside, you should now be able to envision how we can combine synchronization with threading to read messages from the server. But what is a game message? We want something easy to extend, and something that (preferably) doesn&#8217;t rely on newlines to specify message boundaries. Typically, we would use an array of bytes. However, the Ruby 1.8 library code we borrowed doesn&#8217;t support this, forcing us to read and write strings. There are some very good reasons why we don&#8217;t want to force byte arrays into strings:</p>
<ul>
<li>For some reason, I can&#8217;t get the <strong>Socket.read</strong> command to work. This would have allowed us to read <strong>X</strong> bytes from the socket, instead of <strong>recv</strong>&#8216;s “up to <strong>X</strong>” bytes. (I had actually written half this guide based on <strong>read </strong>until I realized it didn&#8217;t work. Silly me.)</li>
<li>If we use <strong>recv </strong>to read bytes, the default for “un-read” bytes is <strong>0</strong>. But what if we actually wanted the number 0? We can get around this (add 1 to each byte sent, or initialize our buffer array with -1 instead of 0) but these “solutions” feel more like hacks –and although I derive great enjoyment from puzzling out another programmer&#8217;s creative solutions, I dislike writing obfuscated code myself.</li>
</ul>
<p>So, we&#8217;ll make this simple: a message is just a string, of the format:</p>
<ul>
<li> <span style="color:#ff0000;"><strong>TYPE</strong></span>:<span style="color:#ff6600;"><strong>xxx</strong></span>:<span style="color:#008000;"><strong>yyy</strong></span>:<span style="color:#3366ff;"><strong>zzz</strong></span>:<strong>\n</strong></li>
</ul>
<p>In other words, a message is composed of a series of strings, separated by colons, with a newline designating the end of the string. The <strong>type </strong>of the message determines how many remaining segments are expected, and what they mean. Here are our message types, and their corresponding data.</p>
<p>The first type is CONNECT_REQUEST, sent when a client wants to log in to the server.</p>
<table style="border:1px solid black;" border="0" width="500">
<tbody>
<tr>
<td style="font-size:1.2em;font-family:monospace;"><strong><em>CONNECT_REQUEST</em></strong></td>
<td style="font-size:1em;"><em>Description</em></td>
</tr>
<tr>
<td style="background:gray;font-size:1em;" align="right" valign="top"><strong>Type</strong></td>
<td style="background:gray;font-size:1em;" valign="top">The string <strong>CREQ</strong></td>
</tr>
<tr>
<td style="font-size:1em;" align="right" valign="top">Avatar ID</td>
<td style="font-size:1em;" valign="top">The ID of the avatar our player has chosen.</td>
</tr>
</tbody>
</table>
<p>The second type is CONNECT_RESPONSE, sent back from the server whenever a client tries to log in.</p>
<table style="border:1px solid black;" border="0" width="500">
<tbody>
<tr>
<td style="font-size:1.2em;font-family:monospace;"><strong><em>CONNECT_RESPONSE</em></strong></td>
<td style="font-size:1em;"><em>Description</em></td>
</tr>
<tr>
<td style="background:gray;font-size:1em;" align="right" valign="top"><strong>Type</strong></td>
<td style="background:gray;font-size:1em;" valign="top">The string <strong>CRES</strong></td>
</tr>
<tr>
<td style="font-size:1em;" align="right" valign="top">Response</td>
<td style="font-size:1em;" valign="top">If <strong>0</strong>, the server refused to allow you to connect. Any other number represents your <strong>ID</strong> on the server. Clients should save this value.</td>
</tr>
</tbody>
</table>
<p>The third type is USER_CONNECT, sent whenever another user has connected to the server to all other players currently online. A series of these messages is also sent from the server to a client that has just logged on, lest he think he logged in to an empty world.</p>
<table style="border:1px solid black;" border="0" width="500">
<tbody>
<tr>
<td style="font-size:1.2em;font-family:monospace;"><strong><em>USER_CONNECT</em></strong></td>
<td style="font-size:1em;"><em>Description</em></td>
</tr>
<tr>
<td style="background:gray;font-size:1em;" align="right" valign="top"><strong>Type</strong></td>
<td style="background:gray;font-size:1em;" valign="top">The string <strong>UCON</strong></td>
</tr>
<tr>
<td style="font-size:1em;" align="right" valign="top">Player ID</td>
<td style="font-size:1em;" valign="top">The ID of the player who has connected.</td>
</tr>
<tr>
<td style="font-size:1em;" align="right" valign="top">Avatar ID</td>
<td style="font-size:1em;" valign="top">The ID of the avatar this player has chosen.</td>
</tr>
</tbody>
</table>
<p>The fourth message type is USER_DISCONNECT, sent when a user has disconnected.</p>
<table style="border:1px solid black;" border="0" width="500">
<tbody>
<tr>
<td style="font-size:1.2em;font-family:monospace;"><strong><em>USER_DISCONNECT</em></strong></td>
<td style="font-size:1em;"><em>Description</em></td>
</tr>
<tr>
<td style="background:gray;font-size:1em;" align="right" valign="top"><strong>Type</strong></td>
<td style="background:gray;font-size:1em;" valign="top">The string <strong>UDIS</strong></td>
</tr>
<tr>
<td style="font-size:1em;" align="right" valign="top">Player ID</td>
<td style="font-size:1em;" valign="top">The ID of the player who has disconnected.</td>
</tr>
</tbody>
</table>
<p>The server manages all user connections, so things like timeouts, etc. are not the client&#8217;s responsibility. In some cases, the server may shut down; if so, it might send USER_DISCONNECT messages to all clients. Thus, if a client receives a USER_DISCONNECT message with its own user ID, it can assume that the server will send no further messages. Moreover, if the client sends a USER_DISCONNECT message to the server, it is probably trying to request a disconnection.</p>
<p>Let&#8217;s actually get some of this code working. First, we&#8217;ll need a <strong>Game_Shared</strong> class and its respective <strong>$game_shared </strong>singleton for containing all our shared objects (which require mutually exclusive access). Add the <strong>Game_Shared</strong> module below <strong>Game_Interpreter</strong>:</p>
<pre><code style="color:black;"><span style="color:#007f00;font-size:9pt;">#==============================================================================</span>
<span style="color:#007f00;font-size:9pt;"># ** Game_Shared</span>
<span style="color:#007f00;font-size:9pt;">#------------------------------------------------------------------------------</span>
<span style="color:#007f00;font-size:9pt;">#  Contains all objects that may be shared among threads, and contains mutexes</span>
<span style="color:#007f00;font-size:9pt;">#  for controllling these accesses.</span>
<span style="color:#007f00;font-size:9pt;">#==============================================================================</span>

<span style="font-weight:bold;color:#0000ef;">class</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ff;">Game_Shared</span>
<span style="color:#808080;">  </span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;"># * Object Initialization</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">initialize</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@read_messages</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">[]</span><span style="color:#808080;">     </span><span style="color:#007f00;font-size:9pt;"># Just read from server</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@read_lock</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Mutex<span style="font-weight:bold;color:#000000;">.</span>new<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;"># Lock for read_messages</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@messages_to_send</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">[]</span><span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;"># To send to server</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@write_lock</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Mutex<span style="font-weight:bold;color:#000000;">.</span>new<span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;"># Lock for messages_to_send</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;"># * Public Accessor Functions --From Server</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">getNextServerMessage</span>
<span style="color:#808080;">    </span>ret<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@read_lock</span><span style="font-weight:bold;color:#000000;">.</span>synchronize<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span>
<span style="color:#808080;">      </span>ret<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#b00080;">@read_messages</span><span style="font-weight:bold;color:#000000;">.</span>shift<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">unless</span><span style="color:#808080;"> </span><span style="color:#b00080;">@read_messages</span><span style="font-weight:bold;color:#000000;">.</span>empty?
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span>ret
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>

<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">queueServerMessage</span><span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@read_lock</span><span style="font-weight:bold;color:#000000;">.</span>synchronize<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span>
<span style="color:#808080;">      </span><span style="color:#b00080;">@read_messages</span><span style="font-weight:bold;color:#000000;">.</span>push<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>

<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;"># * Public Accessor Functions --From Client</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">queueClientMessage</span><span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@write_lock</span><span style="font-weight:bold;color:#000000;">.</span>synchronize<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span>
<span style="color:#808080;">      </span><span style="color:#b00080;">@messages_to_send</span><span style="font-weight:bold;color:#000000;">.</span>push<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>

<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">getNextClientMessage</span>
<span style="color:#808080;">    </span>ret<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@write_lock</span><span style="font-weight:bold;color:#000000;">.</span>synchronize<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span>
<span style="color:#808080;">      </span>ret<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#b00080;">@messages_to_send</span><span style="font-weight:bold;color:#000000;">.</span>shift<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">unless</span><span style="color:#808080;"> </span><span style="color:#b00080;">@messages_to_send</span><span style="font-weight:bold;color:#000000;">.</span>empty?
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span>ret
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>

<span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>To create the singleton, go into <strong>Scene_Title</strong> and find the function <strong>create_game_objects</strong>. Add the following text, right at the end of the function:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#800080;">$game_shared</span><span style="color:#808080;">        </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Game_Shared<span style="font-weight:bold;color:#000000;">.</span>new</code></pre>
<p>Now, we will have access to our singleton object for most of the game. The shared object singleton allows us to read and write messages to and from the server, using arrays to queue the messages properly. It handles all locking internally, so we don&#8217;t need to worry about Mutexes outside of our <strong>Game_Shared</strong> class.</p>
<p>We&#8217;ll also need a <strong>Game_NetMessage</strong> class; add it directly below Game_Shared.</p>
<pre><code style="color:black;"><span style="color:#007f00;">#==============================================================================</span>
<span style="color:#007f00;"># ** Game_NetMessage</span>
<span style="color:#007f00;">#------------------------------------------------------------------------------</span>
<span style="color:#007f00;">#  A light-weight class used to store messages sent to/from the server.</span>
<span style="color:#007f00;">#  Contains helper methods to construct most message types.</span>
<span style="color:#007f00;">#==============================================================================</span>
<span style="font-weight:bold;color:#0000ef;">class</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ff;">Game_NetMessage</span>
<span style="color:#808080;">  </span>
<span style="color:#808080;">  </span><span style="color:#007f00;">#Message types</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>CONNECT_REQUEST<span style="color:#808080;">  </span>
<span style="color:#808080;">    </span><span style="color:#7f007f;">"CREQ"</span><span style="color:#808080;"> </span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>CONNECT_RESPONSE<span style="color:#808080;"> </span>
<span style="color:#808080;">    </span><span style="color:#7f007f;">"CRES"</span><span style="color:#808080;"> </span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>USER_CONNECT<span style="color:#808080;">     </span>
<span style="color:#808080;">    </span><span style="color:#7f007f;">"UCON"</span><span style="color:#808080;"> </span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>USER_DISCONNECT<span style="color:#808080;">  </span>
<span style="color:#808080;">    </span><span style="color:#7f007f;">"UDIS"</span><span style="color:#808080;"> </span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;"> </span><span style="color:#808080;">  </span>
<span style="color:#808080;">  </span><span style="color:#007f00;">#Helper methods</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>Make_ConnectRequest<span style="font-weight:bold;color:#000000;">(</span>avatarID<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#7f007f;">"</span><span style="font-weight:bold;color:#000000;">#{</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>CONNECT_REQUEST<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">:</span><span style="font-weight:bold;color:#000000;">#{</span>avatarID<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">\n"</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>Make_ConnectResponse<span style="font-weight:bold;color:#000000;">(</span>playerNewID<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#7f007f;">"</span><span style="font-weight:bold;color:#000000;">#{</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>CONNECT_RESPONSE<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">:</span><span style="font-weight:bold;color:#000000;">#{</span>playerNewID<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">\n"</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>Make_UserConnect<span style="font-weight:bold;color:#000000;">(</span>playerID<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>avatarID<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#7f007f;">"</span><span style="font-weight:bold;color:#000000;">#{</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>USER_CONNECT<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">:</span><span style="font-weight:bold;color:#000000;">#{</span>playerNID<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">:</span><span style="font-weight:bold;color:#000000;">#{</span>avatarID<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">\n"</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>Make_UserDisconnect<span style="font-weight:bold;color:#000000;">(</span>playerID<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#7f007f;">"</span><span style="font-weight:bold;color:#000000;">#{</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>USER_DISCONNECT<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">:</span><span style="font-weight:bold;color:#000000;">#{</span>playerID<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">\n"</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span><span style="color:#808080;">  </span>
<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>This class functions entirely through static method calls; you&#8217;d never need to create a Game_NetMessage object. Instead, you&#8217;d use it like this:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span>msgToSend<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>Make_ConnectRequest<span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">3</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">  </span><span style="color:#800080;">$game_shared</span><span style="font-weight:bold;color:#000000;">.</span>queueClientMessage<span style="font-weight:bold;color:#000000;">(</span>msgToSend<span style="font-weight:bold;color:#000000;">)</span></code></pre>
<p>&#8230;to make a connection request message and queue it for sending to the server.</p>
<p>All we need now is a $game_network class which performs the following tasks:</p>
<ul>
<li>Create a network thread when the user connects to the server. Destroy this thread (safely) when the user disconnects, or when the server kicks him off.</li>
<li>Maintain some statistics relating to the network: Is it connected? What&#8217;s the latency?</li>
<li>Make sure that the network thread calls <strong>$game_shared.queueServerMessage()</strong> when it receives a message from the server. Make sure it sends data to the server whenever <strong>$game_shared.getNextClientMessage()</strong> returns something non-<strong>nil</strong>.</li>
<li>Catch most bad behavior (like trying to connect to a server multiple times, etc.)</li>
</ul>
<p>Given this brief description, we might create <strong>Game_Network</strong> (placed directly under <strong>Game_NetMessage</strong>) as follows:</p>
<pre><code style="color:black;"><span style="color:#007f00;">#==============================================================================</span>
<span style="color:#007f00;"># ** Game_Network</span>
<span style="color:#007f00;">#------------------------------------------------------------------------------</span>
<span style="color:#007f00;">#  This singleton class controls network access</span>
<span style="color:#007f00;">#==============================================================================</span>
<span style="font-weight:bold;color:#0000ef;">class</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ff;">Game_Network</span>
<span style="color:#808080;">  </span>
<span style="color:#808080;">  </span><span style="color:#007f00;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="color:#007f00;"># * Object Initialization</span>
<span style="color:#808080;">  </span><span style="color:#007f00;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">initialize</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@s</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span><span style="color:#808080;">                </span><span style="color:#007f00;"># Our socket</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">""</span><span style="color:#808080;">               </span><span style="color:#007f00;"># Help with debugging a bit...</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@network_thread</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span><span style="color:#808080;">   </span><span style="color:#007f00;"># Thread is non-nil when we have a server connection</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@kill_thread</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">false</span><span style="color:#808080;">    </span><span style="color:#007f00;"># Set to "true" to gracefully terminate this thread</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@server_message_buffer</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">[]</span><span style="color:#808080;"> </span><span style="color:#007f00;"># Buffer of bytes received from the server</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@my_id</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#800000;">1</span><span style="color:#808080;"> </span><span style="color:#007f00;">#Managed here, not in the game manager</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@connect_mutex</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Mutex<span style="font-weight:bold;color:#000000;">.</span>new
<span style="color:#808080;">    </span><span style="color:#b00080;">@discon_mutex</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Mutex<span style="font-weight:bold;color:#000000;">.</span>new
<span style="color:#808080;">    </span>
<span style="color:#808080;">    </span><span style="color:#007f00;">#Always start OFF</span>
<span style="color:#808080;">    </span><span style="color:#800080;">$game_switches</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">2</span><span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">false</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span>
<span style="color:#808080;">  </span><span style="color:#007f00;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="color:#007f00;"># * Main Functionality</span>
<span style="color:#808080;">  </span><span style="color:#007f00;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">handle_messages</span>
<span style="color:#808080;">    </span><span style="color:#007f00;">#Write while we have messages to send</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"handle_messages():send"</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">while</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">true</span><span style="color:#808080;"> </span><span style="color:#007f00;">#Can always send</span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Anything to send?</span>
<span style="color:#808080;">      </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"handle_messages():check to send"</span>
<span style="color:#808080;">      </span>clientMsg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_shared</span><span style="font-weight:bold;color:#000000;">.</span>getNextClientMessage
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">break</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">unless</span><span style="color:#808080;"> </span>clientMsg
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Send it</span>
<span style="color:#808080;">      </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"handle_messages():send messages"</span>
<span style="color:#808080;">      </span><span style="color:#b00080;">@s</span><span style="font-weight:bold;color:#000000;">.</span>send<span style="font-weight:bold;color:#000000;">(</span>clientMsg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">    </span>
<span style="color:#808080;">    </span><span style="color:#007f00;">#Read while we have data available</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"handle_messages():receive"</span>
<span style="color:#808080;">    </span>partial_message<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">while</span><span style="color:#808080;"> </span><span style="color:#b00080;">@s</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">and</span><span style="color:#808080;"> </span><span style="color:#b00080;">@s</span><span style="font-weight:bold;color:#000000;">.</span>ready?<span style="color:#808080;"> </span><span style="color:#007f00;">#Can only recv if the socket is ready</span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Read as many remaining bytes as possible</span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#NOTE: Using -1 means that there will always be a '' entry if </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#      our string originally ended in \n</span>
<span style="color:#808080;">      </span>readStr<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#b00080;">@s</span><span style="font-weight:bold;color:#000000;">.</span>recv<span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">0x1024</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span>readStr<span style="font-weight:bold;color:#000000;">.</span>gsub<span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">0.chr</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#7f007f;">''</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#TEMP</span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#print "Read: #{readStr}" unless readStr.empty?</span>
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Continue?</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">next</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>readStr<span style="font-weight:bold;color:#000000;">.</span>empty?
<span style="color:#808080;">      </span>lines<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>readStr<span style="font-weight:bold;color:#000000;">.</span>split<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"\n"</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Any partial message to complete?</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>partial_message
<span style="color:#808080;">        </span>lines<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>partial_message<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>lines<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">]</span>
<span style="color:#808080;">        </span>partial_message<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Is the final message partial? If so, defer processing till later</span>
<span style="color:#808080;">      </span>partial_message<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>lines<span style="font-weight:bold;color:#000000;">.</span>pop<span style="color:#808080;"> </span>
<span style="color:#808080;">      </span>partial_message<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>partial_message<span style="font-weight:bold;color:#000000;">.</span>empty?
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Ok, we've got a series of messages. Queue them for the client</span>
<span style="color:#808080;">      </span>lines<span style="font-weight:bold;color:#000000;">.</span>each<span style="font-weight:bold;color:#000000;">{|</span>message<span style="font-weight:bold;color:#000000;">|</span><span style="color:#808080;"> </span>
<span style="color:#808080;">        </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"handle_messages():process single message"</span>
<span style="color:#808080;">        </span>
<span style="color:#808080;">        </span><span style="color:#007f00;">#Split this one too; remove newline</span>
<span style="color:#808080;">        </span>segments<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>message<span style="font-weight:bold;color:#000000;">.</span>rstrip<span style="font-weight:bold;color:#000000;">.</span>split<span style="font-weight:bold;color:#000000;">(</span><span style="color:#000000;background:none repeat scroll 0 0 #a0ffa0;text-decoration:inherit;">/:/</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span>
<span style="color:#808080;">        </span><span style="color:#007f00;">#TEMP: DEBUG</span>
<span style="color:#808080;">        </span><span style="color:#007f00;">#print "Message: #{message}"</span>
<span style="color:#808080;">        </span>
<span style="color:#808080;">        </span><span style="color:#007f00;">#We don't always post it</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">]==</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>CONNECT_RESPONSE
<span style="color:#808080;">          </span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">].</span>to_i
<span style="color:#808080;">          </span><span style="color:#b00080;">@my_id</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">&gt;</span><span style="color:#808080;"> </span><span style="color:#800000;">0</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">elsif</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">]==</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>USER_DISCONNECT<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">and</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">].</span>to_i<span style="font-weight:bold;color:#000000;">==</span><span style="color:#b00080;">@my_id</span>
<span style="color:#808080;">          </span>destroy_thread<span style="font-weight:bold;color:#000000;">()</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">else</span>
<span style="color:#808080;">          </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"handle_messages():try to queue"</span>
<span style="color:#808080;">          </span><span style="color:#800080;">$game_shared</span><span style="font-weight:bold;color:#000000;">.</span>queueServerMessage<span style="font-weight:bold;color:#000000;">(</span>message<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="color:#808080;">  </span>
<span style="color:#808080;">  </span>
<span style="color:#808080;">  </span><span style="color:#007f00;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="color:#007f00;"># * Thread access</span>
<span style="color:#808080;">  </span><span style="color:#007f00;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">connect</span><span style="font-weight:bold;color:#000000;">(</span>serveraddr<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@connect_mutex</span><span style="font-weight:bold;color:#000000;">.</span>synchronize<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="color:#007f00;">#Keep re-entrant calls legal.</span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Error?</span>
<span style="color:#808080;">      </span>raise<span style="color:#808080;"> </span><span style="color:#7f007f;">"Network error: already connected"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span><span style="color:#b00080;">@network_thread</span>
<span style="color:#808080;">    </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Parse out the port from the server address</span>
<span style="color:#808080;">      </span>serverparts<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>serveraddr<span style="font-weight:bold;color:#000000;">.</span>split<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">':'</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>serverparts<span style="font-weight:bold;color:#000000;">.</span>length<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">!=</span><span style="color:#808080;"> </span><span style="color:#800000;">2</span>
<span style="color:#808080;">        </span>raise<span style="color:#808080;"> </span><span style="color:#7f007f;">"Network error: cannot connect to \"</span><span style="font-weight:bold;color:#000000;">#{</span>serveraddr<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">\", bad address"</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">return</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">      </span>serverparts<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>serverparts<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">].</span>to_i
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Create a network thread to connect and parse messages</span>
<span style="color:#808080;">      </span><span style="color:#007f00;"># Note that threads must handle their own exceptions</span>
<span style="color:#808080;">      </span><span style="color:#b00080;">@kill_thread</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">false</span>
<span style="color:#808080;">      </span><span style="color:#b00080;">@network_thread</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Thread<span style="font-weight:bold;color:#000000;">.</span>new<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">begin</span>
<span style="color:#808080;">          </span><span style="color:#007f00;">#Connect</span>
<span style="color:#808080;">          </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"connect():init connect"</span>
<span style="color:#808080;">          </span><span style="color:#b00080;">@s</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>TCPSocket<span style="font-weight:bold;color:#000000;">.</span>new<span style="font-weight:bold;color:#000000;">(</span>serverparts<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">],</span><span style="color:#808080;"> </span>serverparts<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">])</span>
<span style="color:#808080;">          </span><span style="color:#800080;">$game_switches</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">2</span><span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">true</span>
<span style="color:#808080;">          </span>
<span style="color:#808080;">          </span><span style="color:#007f00;">#Send first message: whoami?</span>
<span style="color:#808080;">          </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"connect():send first message"</span>
<span style="color:#808080;">          </span>avatarID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">]</span>
<span style="color:#808080;">          </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>Make_ConnectRequest<span style="font-weight:bold;color:#000000;">(</span>avatarID<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">          </span><span style="color:#800080;">$game_shared</span><span style="font-weight:bold;color:#000000;">.</span>queueClientMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">          </span>
<span style="color:#808080;">          </span><span style="color:#007f00;">#Process</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#0000ef;">while</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">true</span>
<span style="color:#808080;">            </span><span style="color:#007f00;">#Done?</span>
<span style="color:#808080;">            </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"connect():check if done"</span>
<span style="color:#808080;">            </span><span style="color:#b00080;">@discon_mutex</span><span style="font-weight:bold;color:#000000;">.</span>synchronize<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">              </span><span style="font-weight:bold;color:#0000ef;">break</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span><span style="color:#b00080;">@kill_thread</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">            </span>
<span style="color:#808080;">            </span><span style="color:#007f00;">#Process any messages</span>
<span style="color:#808080;">            </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"connect():call handle_messages()"</span>
<span style="color:#808080;">            </span>handle_messages<span style="font-weight:bold;color:#000000;">()</span>
<span style="color:#808080;">            </span><span style="color:#b00080;">@loc</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"connect():returned from handle_messages()"</span>
<span style="color:#808080;">            </span>sleep<span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">rescue</span><span style="color:#808080;"> </span>StandardError<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=&gt;</span><span style="color:#808080;"> </span>err
<span style="color:#808080;">          </span><span style="color:#007f00;">#Print an error, destroy this thread</span>
<span style="color:#808080;">          </span>print<span style="color:#808080;"> </span><span style="color:#7f007f;">"Exception in network thread(</span><span style="font-weight:bold;color:#000000;">#{</span><span style="color:#b00080;">@loc</span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">): </span><span style="font-weight:bold;color:#000000;">#{</span>err<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;">\n"</span>
<span style="color:#808080;">          </span><span style="color:#b00080;">@network_thread</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">ask_to_disconnect</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span><span style="color:#b00080;">@my_id</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">!=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#800000;">1</span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Queue a closing message</span>
<span style="color:#808080;">      </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>Make_UserDisconnect<span style="font-weight:bold;color:#000000;">(</span><span style="color:#b00080;">@my_id</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span><span style="color:#800080;">$game_shared</span><span style="font-weight:bold;color:#000000;">.</span>queueClientMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">else</span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Just kill the thread</span>
<span style="color:#808080;">      </span>destroy_thread<span style="font-weight:bold;color:#000000;">()</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">destroy_thread</span>
<span style="color:#808080;">    </span><span style="color:#007f00;">#Signal the thread to stop</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@discon_mutex</span><span style="font-weight:bold;color:#000000;">.</span>synchronize<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span><span style="color:#b00080;">@kill_thread</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">true</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span><span style="color:#b00080;">@network_thread</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">and</span><span style="color:#808080;"> </span><span style="color:#b00080;">@network_thread</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">!=</span><span style="color:#808080;"> </span>Thread<span style="font-weight:bold;color:#000000;">.</span>current
<span style="color:#808080;">      </span><span style="color:#b00080;">@network_thread</span><span style="font-weight:bold;color:#000000;">.</span>join
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@s</span><span style="font-weight:bold;color:#000000;">.</span>close<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span><span style="color:#b00080;">@s</span>
<span style="color:#808080;">    </span>
<span style="color:#808080;">    </span><span style="color:#007f00;">#Rest to nil</span>
<span style="color:#808080;">    </span><span style="color:#800080;">$game_switches</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">2</span><span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">false</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@network_thread</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@s</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span>
<span style="color:#808080;">    </span><span style="color:#b00080;">@my_id</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#800000;">1</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span>
<span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>Ok, that was far longer than I&#8217;d hoped, but that&#8217;s probably because my understanding of Ruby is pretty lousy. Before we analyze it, add the following to the end of <strong>Scene_Title</strong>&#8216;s <strong>create_game_objects</strong> function:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#800080;">$game_network</span><span style="color:#808080;">       </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Game_Network<span style="font-weight:bold;color:#000000;">.</span>new</code></pre>
<p>This creates our singleton object; now, let&#8217;s talk about the main code. First, some disclaimers: even though I&#8217;ve added a few mutexes, this code definitely isn&#8217;t thread-safe. If you call <strong>connect() </strong>and<strong> destroy_thread()</strong> multiple times and quickly, the code will likely destabilize. However, it probably won&#8217;t mess up under normal usage conditions. There&#8217;s only three  main differences between this code and the snippet we used in <strong>Step 3</strong> to test our network connection:</p>
<ul>
<li>We borrowed the message loop from RMX-OS&#8217;s <strong>listen </strong>method, although we changed a few things to suit our purposes.</li>
<li>Although the game engine handles most messages, our <strong>Game_Network</strong> class automates connection/disconnection requests and the storage of our own ID. We only have to call the <strong>connect </strong>and <strong>ask_to_disconnect</strong> methods (and read all other relevant messages in the game thread, of course) for communication to work.</li>
<li>We use <strong>Switch 2</strong>, which you should now name <strong>Network ON</strong>, to store the status of the network. This makes it easy for NPCs to react to “being online” without requiring them to use any scripting.</li>
</ul>
<p>The client-server communication is only halfway complete; we also have to create client messages to send and respond to server messages. This will occur inside the game engine. Briefly, the following needs to happen:</p>
<ul>
<li>Call <strong>connect </strong>and <strong>ask_to_disconnect </strong>when appropriate.</li>
<li>Handle USER_CONNECT and USER_DISCONNECT messages (and discard or err on unknown messages) at some central point in the client code.</li>
</ul>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } --> <!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } 		A:link { so-language: zxx } -->That&#8217;s it. Our client sends no outgoing messages that aren&#8217;t handled in<strong> Game_Network</strong> (for now). The question remains: where should we check messages? It should be somewhere central, and somewhere accessed often (but not too often). I recommend <strong>Game_Map</strong><span style="font-family:Times New Roman,serif;">´</span>s <strong>update </strong>method. Add the following line to <strong>Game_Map</strong><span style="font-family:Times New Roman,serif;">´</span>s <strong>update </strong>method, after <strong>update_scroll</strong> and before <strong>update_events</strong>:</p>
<pre><code style="color:black;">  update_network</code></pre>
<p>Now, somewhere in that module, add the code for <strong>update_network</strong>:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#007f00;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="color:#007f00;"># * Update Network: Read messages  (write as-needed elsewhere)</span>
<span style="color:#808080;">  </span><span style="color:#007f00;">#--------------------------------------------------------------------------</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">update_network</span>
<span style="color:#808080;">    </span><span style="color:#007f00;">#"Process no more than X messages"</span>
<span style="color:#808080;">    </span>nextMsg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">nil</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">for</span><span style="color:#808080;"> </span>i<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">in</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">1.</span><span style="font-weight:bold;color:#000000;">.</span><span style="color:#800000;">10</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Read the next message</span>
<span style="color:#808080;">      </span>nextMsg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_shared</span><span style="font-weight:bold;color:#000000;">.</span>getNextServerMessage
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">break</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">unless</span><span style="color:#808080;"> </span>nextMsg
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Split</span>
<span style="color:#808080;">      </span>segments<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>nextMsg<span style="font-weight:bold;color:#000000;">.</span>rstrip<span style="font-weight:bold;color:#000000;">.</span>split<span style="font-weight:bold;color:#000000;">(</span><span style="color:#000000;background:none repeat scroll 0 0 #a0ffa0;text-decoration:inherit;">/:/</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span>
<span style="color:#808080;">      </span><span style="color:#007f00;">#Process</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">]==</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>CONNECT_REQUEST
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">next</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">elsif</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">]==</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>CONNECT_RESPONSE
<span style="color:#808080;">          </span><span style="color:#007f00;">#Always refresh</span>
<span style="color:#808080;">          </span><span style="color:#800080;">$game_map</span><span style="font-weight:bold;color:#000000;">.</span>need_refresh<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">true</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">elsif</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">]==</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>USER_CONNECT
<span style="color:#808080;">        </span><span style="color:#007f00;">#Add an NPC to the map with the right picture and behavior.</span>
<span style="color:#808080;">        </span><span style="color:#007f00;">#In range (3,9) , (11,14)</span>
<span style="color:#808080;">        </span>avtID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">].</span>to_i<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#808080;"> </span><span style="color:#800000;">1</span>
<span style="color:#808080;">        </span>plrID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">2</span><span style="font-weight:bold;color:#000000;">].</span>to_i
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>avtID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">&lt;</span><span style="color:#808080;"> </span><span style="color:#b00080;">@max_network_npcs</span>
<span style="color:#808080;">          </span><span style="color:#007f00;">#Get the event, place it</span>
<span style="color:#808080;">          </span><span style="color:#007f00;">#print "Moving NPC #{@net_npc_start + avtID}"</span>
<span style="color:#808080;">          </span>newNPC<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#b00080;">@events</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#b00080;">@net_npc_start</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>avtID<span style="font-weight:bold;color:#000000;">]</span>
<span style="color:#808080;">          </span>moveNPCRandom<span style="font-weight:bold;color:#000000;">(</span>newNPC<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#800000;">3</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#800000;">9</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#800000;">8</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#800000;">5</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">          </span>
<span style="color:#808080;">          </span><span style="color:#007f00;">#Set its variable flag (for picture)</span>
<span style="color:#808080;">          </span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#b00080;">@net_npc_picvar_start</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>avtID<span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>plrID
<span style="color:#808080;">          </span>
<span style="color:#808080;">          </span><span style="color:#007f00;">#Always refresh</span>
<span style="color:#808080;">          </span><span style="color:#800080;">$game_map</span><span style="font-weight:bold;color:#000000;">.</span>need_refresh<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">true</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">elsif</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">]==</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>USER_DISCONNECT
<span style="color:#808080;">        </span><span style="color:#007f00;">#Remove the NPC</span>
<span style="color:#808080;">        </span>avtID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">].</span>to_i<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#808080;"> </span><span style="color:#800000;">1</span>
<span style="color:#808080;">        </span><span style="color:#b00080;">@events</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#b00080;">@net_npc_start</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>avtID<span style="font-weight:bold;color:#000000;">].</span>moveto<span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">        </span>
<span style="color:#808080;">        </span><span style="color:#007f00;">#Remove its picture</span>
<span style="color:#808080;">        </span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#b00080;">@net_npc_picvar_start</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>avtID<span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800000;">0</span>
<span style="color:#808080;">        </span>
<span style="color:#808080;">        </span><span style="color:#007f00;">#Always refresh</span>
<span style="color:#808080;">        </span><span style="color:#800080;">$game_map</span><span style="font-weight:bold;color:#000000;">.</span>need_refresh<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">true</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">end</span><span style="color:#808080;">  </span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>This code is not complicated, but let&#8217;s review it anyway.</p>
<ul>
<li>First, we read through all available messages. Since a very busy server will probably never stop spawning messages, we limit our processing to 10 messages per game “tick” (which should equate to 600 messages processed per second). We might have to change this later.</li>
<li>Next, we react to each message:
<ul>
<li>When a user connects, we take a pre-defined npc and move it to a random location between (3,9) and (11, 14). We will create placeholder events later. We then set a pre-defined variable to be equal to the avatar&#8217;s ID. Presumably, our pre-defined event will have a page for each avatarID with its respective walkabout.</li>
<li>When a user disconnects, we teleport that NPC to the top-left corner of the map, and set its avatar ID variable to 0, thus making it invisible.</li>
</ul>
</li>
<li>A note about <strong>$game_map.need_refresh</strong>; this function basically forces several computationally-intensive checks of the map to re-occur on the next map update. In particular, we use it to make sure that each event is updated to the proper page when our <strong>NPC-Avatar ID</strong> variable is set.</li>
</ul>
<p>This code requires the the function <strong>moveNPCRandom</strong>; for now, just add this prototype somewhere in the <strong>Game_Map</strong> class:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">#For now, just non-random is ok</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">moveNPCRandom</span><span style="font-weight:bold;color:#000000;">(</span>npc<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>xMin<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>yMin<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>width<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>height<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">for</span><span style="color:#808080;"> </span>y<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">in</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>yMin<span style="font-weight:bold;color:#000000;">..</span>yMin<span style="font-weight:bold;color:#000000;">+</span>height<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">for</span><span style="color:#808080;"> </span>x<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">in</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>xMin<span style="font-weight:bold;color:#000000;">..</span>xMin<span style="font-weight:bold;color:#000000;">+</span>width<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span>events_xy<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>y<span style="font-weight:bold;color:#000000;">).</span>empty?
<span style="color:#808080;">          </span>npc<span style="font-weight:bold;color:#000000;">.</span>moveto<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>y<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#0000ef;">return</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">end</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#0000ef;">end</span>

<span style="color:#808080;">    </span><span style="color:#007f00;font-size:9pt;">#If all else fails, just place it in the middle (there will be a conflict)</span>
<span style="color:#808080;">    </span>npc<span style="font-weight:bold;color:#000000;">.</span>moveto<span style="font-weight:bold;color:#000000;">(</span>xMin<span style="font-weight:bold;color:#000000;">+</span>width<span style="font-weight:bold;color:#000000;">/</span><span style="color:#800000;">2</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>yMin<span style="font-weight:bold;color:#000000;">+</span>height<span style="font-weight:bold;color:#000000;">/</span><span style="color:#800000;">2</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>Re-using existing NPCs is not the best way of doing things; unfortunately, the <strong>Event </strong>class is internal to RPG Maker and cannot (easily) be changed. For our proof-of-concept, however, it will work fine.</p>
<p>Before we talk about the variables <strong>@net_npc_start</strong> and so on, let&#8217;s add the placeholder NPCs to the map. Create five npcs and place them somewhere near the top of the map, like so:</p>
<div id="attachment_271" class="wp-caption alignnone" style="width: 285px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_newnpcs.png"><img class="size-medium wp-image-271" title="post10_prot2_newnpcs" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_newnpcs.png?w=275&#038;h=197" alt="" width="275" height="197" /></a><p class="wp-caption-text">Put our five dummy NPCs out of range. Make sure they have increasing IDs.</p></div>
<p>You <em><strong>must </strong></em>create these NPCs in order, so that they have<em><strong> increasing IDs</strong></em>. Confirm that they do, indeed, have increasing events IDs (they should be named Event 006, Event 007, etc.). The first NPC should be set up in this way:</p>
<ul>
<li>Page 1 has no graphic, and is below the hero. (You might add a graphic for debugging purposes, just so you can confirm when this NPC moves.)</li>
<li>Page 2 checks if <span style="color:#0000ff;"><strong>variable 10</strong></span> (called <span style="color:#0000ff;"><strong>NPC1-Avatar ID</strong></span>) is <span style="color:#ff0000;"><strong>1 or above</strong></span>. It is a<strong> random-walk</strong> NPC at the <strong>same level</strong> as the hero, and has the<span style="color:#ff0000;"><strong> first hero&#8217;s walkabout</strong></span> as its graphic. Its event code consists of two lines:
<ul>
<li>Set <strong>variable 9</strong> (called <strong>CurrTalk NPC</strong>) to be equal to <span style="color:#0000ff;"><strong>6</strong></span>. (Or, whatever your NPC&#8217;s id is).</li>
<li>Call <strong>Common Event 4</strong> (called <strong>Show NPC Message</strong>)</li>
</ul>
</li>
<li>Pages 3 through 6 are just like page 2, except all the <span style="color:#ff0000;"><strong>red </strong></span>text is incremented by one. In other words, there is a page for each hero graphic.</li>
</ul>
<p>The first NPC should look something like this, on the last page:</p>
<div id="attachment_272" class="wp-caption alignnone" style="width: 369px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_npc1lastpage.png"><img class="size-medium wp-image-272" title="post10_prot2_npc1lastpage" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_npc1lastpage.png?w=359&#038;h=289" alt="" width="359" height="289" /></a><p class="wp-caption-text">The last page of the first NPC in our series of dummy NPCs.</p></div>
<p>Now, alter the other NPCs, except increment the <span style="color:#0000ff;"><strong>blue </strong></span>text by one. You&#8217;re basically creating a new NPC for each character in the virtual world, with a variable to change its appearance. The common event <strong>Show NPC Message</strong> will be used to centralize all communication.</p>
<p>Finally, go back to your <strong>Game_Map </strong>code, and put the following in the <strong>initialize </strong>method, directly before the call to <strong>create_vehicles</strong>:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#b00080;">@max_network_npcs</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800000;">5</span><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">#How many max?</span>
<span style="color:#808080;">  </span><span style="color:#b00080;">@net_npc_start</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800000;">6</span><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">#Start at ID 6</span>
<span style="color:#808080;">  </span><span style="color:#b00080;">@net_npc_picvar_start</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800000;">10</span><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">#Start at ID 10</span></code></pre>
<p>You might have to change <strong>@net_npc_start</strong> if your first NPC&#8217;s ID was something other than 6.</p>
<p>All that&#8217;s left is to hook up <strong>$game_network.connect() </strong>and the disconnect function. Open the database (F9) and go to the <strong>Common Events</strong> tab. Go to Common Event 1, &#8220;Connect to a server&#8221; menu, and add the following to the existing “Choice” command.</p>
<ul>
<li>For “When \N[7]”, add the script:
<pre><code style="color:black;"><span style="color:#808080;">  </span>npcName<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_actors</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">7</span><span style="font-weight:bold;color:#000000;">].</span>name
<span style="color:#808080;">  </span><span style="color:#800080;">$game_network</span><span style="font-weight:bold;color:#000000;">.</span>connect<span style="color:#808080;"> </span>npcName</code></pre>
</li>
<li>For “When \N[8]”, add the script:
<pre><code style="color:black;"><span style="color:#808080;">  </span>npcName<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_actors</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">8</span><span style="font-weight:bold;color:#000000;">].</span>name
<span style="color:#808080;">  </span><span style="color:#800080;">$game_network</span><span style="font-weight:bold;color:#000000;">.</span>connect<span style="color:#808080;"> </span>npcName</code></pre>
</li>
</ul>
<p>Now, go to the network NPC you created earlier, and add a new page with the same graphic. For this page&#8217;s “conditions”, select “<strong>Switch 2</strong> (Network ON) is ON”. Then, add the following event commands:</p>
<div id="attachment_268" class="wp-caption alignnone" style="width: 403px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_disconnpc.png"><img class="size-medium wp-image-268" title="post10_prot2_disconnpc" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_disconnpc.png?w=393&#038;h=316" alt="" width="393" height="316" /></a><p class="wp-caption-text">Our &quot;Connect&quot; NPC will ask us to disconnect if already connected.</p></div>
<p>Described briefly:</p>
<ul>
<li>The NPC will ask if you want to disconnect. If you say “Yes”, he will call <strong>$game_network.ask_to_disconnect</strong>.</li>
</ul>
<p>At this point, our prototype is complete. The only thing missing is the server. Our server will be written in Java, and it only performs three important functions:</p>
<ul>
<li>Track connection requests and responses, as well as disconnections and timeouts.</li>
<li>Maintain a list of all online users and their avatars.</li>
<li>Perform required bookkeeping; making sure that users receive all relevant messages.</li>
</ul>
<p>Here&#8217;s the code for this in Java:</p>
<pre><code style="color:black;"><span style="font-weight:bold;color:#00007f;">import</span><span style="color:#808080;"> </span>java<span style="font-weight:bold;color:#000000;">.</span>io<span style="font-weight:bold;color:#000000;">.*;</span>
<span style="font-weight:bold;color:#00007f;">import</span><span style="color:#808080;"> </span>java<span style="font-weight:bold;color:#000000;">.</span>net<span style="font-weight:bold;color:#000000;">.*;</span>
<span style="font-weight:bold;color:#00007f;">import</span><span style="color:#808080;"> </span>java<span style="font-weight:bold;color:#000000;">.</span>util<span style="font-weight:bold;color:#000000;">.*;</span>
<span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">class</span><span style="color:#808080;"> </span>VXServer<span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">implements</span><span style="color:#808080;"> </span>Runnable<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">//Data</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>port<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span>Hashtable<span style="font-weight:bold;color:#000000;">&lt;</span>Integer<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>GameConnection<span style="font-weight:bold;color:#000000;">&gt;</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">;</span>

<span style="color:#808080;">  </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span>VXServer<span style="font-weight:bold;color:#000000;">(</span>String<span style="color:#808080;"> </span>port<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>port<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Integer<span style="font-weight:bold;color:#000000;">.</span>parseInt<span style="font-weight:bold;color:#000000;">(</span>port<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>players<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>Hashtable<span style="font-weight:bold;color:#000000;">&lt;</span>Integer<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>GameConnection<span style="font-weight:bold;color:#000000;">&gt;();</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#000000;">}</span>

<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">//Get the next available ID</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>getNextID<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>nextID<span style="font-weight:bold;color:#000000;">=</span><span style="color:#007f7f;">1</span><span style="font-weight:bold;color:#000000;">;</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">;</span>nextID<span style="font-weight:bold;color:#000000;">++)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(!</span>players<span style="font-weight:bold;color:#000000;">.</span>containsKey<span style="font-weight:bold;color:#000000;">(</span>nextID<span style="font-weight:bold;color:#000000;">))</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">return</span><span style="color:#808080;"> </span>nextID<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">//Repeatedly accept new connections</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>run<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">try</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span>ServerSocket<span style="color:#808080;"> </span>mainSocket<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>ServerSocket<span style="font-weight:bold;color:#000000;">(</span>port<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"Server started on local port: "</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>port<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">( ; ; )</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span>Socket<span style="color:#808080;"> </span>childSocket<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>mainSocket<span style="font-weight:bold;color:#000000;">.</span>accept<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>getNextID<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">        </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"New player connected; given id: "</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>id<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">        </span>GameConnection<span style="color:#808080;"> </span>gc<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>GameConnection<span style="font-weight:bold;color:#000000;">(</span>childSocket<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>id<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">synchronized</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>players<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">          </span>players<span style="font-weight:bold;color:#000000;">.</span>put<span style="font-weight:bold;color:#000000;">(</span>id<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>gc<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">          </span>gc<span style="font-weight:bold;color:#000000;">.</span>startThreads<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">catch</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>IOException<span style="color:#808080;"> </span>ex<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"Main socket error: "</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>ex<span style="font-weight:bold;color:#000000;">.</span>toString<span style="font-weight:bold;color:#000000;">());</span>
<span style="color:#808080;">      </span>ex<span style="font-weight:bold;color:#000000;">.</span>printStackTrace<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>removeClient<span style="font-weight:bold;color:#000000;">(</span>String<span style="color:#808080;"> </span>reason<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>id<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">    </span>String<span style="color:#808080;"> </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"UDIS:"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>id<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span>GameConnection<span style="color:#808080;"> </span>remPlayer<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">null</span><span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">synchronized</span><span style="font-weight:bold;color:#000000;">(</span>players<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span><span style="color:#007f00;font-size:9pt;">//Remove from hash</span>
<span style="color:#808080;">      </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"Closing client["</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"] - "</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>reason<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span>remPlayer<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>remove<span style="font-weight:bold;color:#000000;">(</span>id<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span><span style="color:#007f00;font-size:9pt;">//Send a message to all other players</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>x<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">:</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>keySet<span style="font-weight:bold;color:#000000;">())</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>sendMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="color:#007f00;font-size:9pt;">//Disconnect</span>
<span style="color:#808080;">    </span>remPlayer<span style="font-weight:bold;color:#000000;">.</span>stopThreads<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#000000;">}</span>

<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">//Main method; processing starts here</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">static</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>main<span style="font-weight:bold;color:#000000;">(</span>String<span style="font-weight:bold;color:#000000;">[]</span><span style="color:#808080;"> </span>args<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>args<span style="font-weight:bold;color:#000000;">.</span>length<span style="font-weight:bold;color:#000000;">&lt;</span><span style="color:#007f7f;">1</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>Thread<span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>VXServer<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"7689"</span><span style="font-weight:bold;color:#000000;">)).</span>start<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">else</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>Thread<span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>VXServer<span style="font-weight:bold;color:#000000;">(</span>args<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">0</span><span style="font-weight:bold;color:#000000;">])).</span>start<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#000000;">}</span>

<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">//////////////////</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">//Helper class</span>
<span style="color:#808080;">  </span><span style="color:#007f00;font-size:9pt;">//////////////////</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#00007f;">class</span><span style="color:#808080;"> </span>GameConnection<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">    </span><span style="color:#007f00;font-size:9pt;">//Data</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>id<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>avatarID<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span>Socket<span style="color:#808080;"> </span>s<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">boolean</span><span style="color:#808080;"> </span>active<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span>BufferedReader<span style="color:#808080;"> </span>readStream<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span>BufferedWriter<span style="color:#808080;"> </span>writeStream<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span>Thread<span style="color:#808080;"> </span>readFromClient<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span>Thread<span style="color:#808080;"> </span>writeToClient<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span>ArrayList<span style="font-weight:bold;color:#000000;">&lt;</span>String<span style="font-weight:bold;color:#000000;">&gt;</span><span style="color:#808080;"> </span>pendingToSend<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span>GameConnection<span style="font-weight:bold;color:#000000;">(</span>Socket<span style="color:#808080;"> </span>s<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>id<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>s<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>s<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>id<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>avatarID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>avatarID<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">try</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>readStream<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>BufferedReader<span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>InputStreamReader<span style="font-weight:bold;color:#000000;">(</span>s<span style="font-weight:bold;color:#000000;">.</span>getInputStream<span style="font-weight:bold;color:#000000;">()));</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>writeStream<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>BufferedWriter<span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>OutputStreamWriter<span style="font-weight:bold;color:#000000;">(</span>s<span style="font-weight:bold;color:#000000;">.</span>getOutputStream<span style="font-weight:bold;color:#000000;">()));</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">catch</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>IOException<span style="color:#808080;"> </span>ex<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">throw</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>RuntimeException<span style="font-weight:bold;color:#000000;">(</span>ex<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>pendingToSend<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>ArrayList<span style="font-weight:bold;color:#000000;">&lt;</span>String<span style="font-weight:bold;color:#000000;">&gt;();</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>readFromClient<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>Thread<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>run<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">while</span><span style="font-weight:bold;color:#000000;">(</span>active<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span>readLoop<span style="font-weight:bold;color:#000000;">();</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">};</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>writeToClient<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">new</span><span style="color:#808080;"> </span>Thread<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>run<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">while</span><span style="font-weight:bold;color:#000000;">(</span>active<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span>writeLoop<span style="font-weight:bold;color:#000000;">();</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">};</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>startThreads<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>active<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>true<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>readFromClient<span style="font-weight:bold;color:#000000;">.</span>start<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>writeToClient<span style="font-weight:bold;color:#000000;">.</span>start<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>stopThreads<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>active<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>false<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">try</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>readFromClient<span style="font-weight:bold;color:#000000;">.</span>join<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>writeToClient<span style="font-weight:bold;color:#000000;">.</span>join<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">catch</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>InterruptedException<span style="color:#808080;"> </span>ex<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{}</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">try</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>s<span style="font-weight:bold;color:#000000;">.</span>close<span style="font-weight:bold;color:#000000;">();</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">catch</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>IOException<span style="color:#808080;"> </span>ex<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>sendMessage<span style="font-weight:bold;color:#000000;">(</span>String<span style="color:#808080;"> </span>msg<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">synchronized</span><span style="font-weight:bold;color:#000000;">(</span>pendingToSend<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span>pendingToSend<span style="font-weight:bold;color:#000000;">.</span>add<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>writeLoop<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span><span style="color:#007f00;font-size:9pt;">//Wait for a message (messages are NON_null terminated)</span>
<span style="color:#808080;">      </span>String<span style="color:#808080;"> </span>nextMsg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">null</span><span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">( ;</span>nextMsg<span style="font-weight:bold;color:#000000;">==</span><span style="font-weight:bold;color:#00007f;">null</span><span style="font-weight:bold;color:#000000;">; )</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">synchronized</span><span style="font-weight:bold;color:#000000;">(</span>pendingToSend<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(!</span>pendingToSend<span style="font-weight:bold;color:#000000;">.</span>isEmpty<span style="font-weight:bold;color:#000000;">())</span>
<span style="color:#808080;">            </span>nextMsg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>pendingToSend<span style="font-weight:bold;color:#000000;">.</span>remove<span style="font-weight:bold;color:#000000;">(</span><span style="color:#007f7f;">0</span><span style="font-weight:bold;color:#000000;">).</span>trim<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"\n"</span><span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>nextMsg<span style="font-weight:bold;color:#000000;">==</span><span style="font-weight:bold;color:#00007f;">null</span><span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">try</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span>Thread<span style="font-weight:bold;color:#000000;">.</span>sleep<span style="font-weight:bold;color:#000000;">(</span><span style="color:#007f7f;">10</span><span style="font-weight:bold;color:#000000;">);</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">catch</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>InterruptedException<span style="color:#808080;"> </span>ex<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">      </span><span style="color:#007f00;font-size:9pt;">//TEMP</span>
<span style="color:#808080;">      </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"Sent message: "</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>nextMsg<span style="font-weight:bold;color:#000000;">.</span>trim<span style="font-weight:bold;color:#000000;">());</span>

<span style="color:#808080;">      </span><span style="color:#007f00;font-size:9pt;">//Send message</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">try</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span>writeStream<span style="font-weight:bold;color:#000000;">.</span>write<span style="font-weight:bold;color:#000000;">(</span>nextMsg<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="color:#007f7f;">0</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>nextMsg<span style="font-weight:bold;color:#000000;">.</span>length<span style="font-weight:bold;color:#000000;">());</span>
<span style="color:#808080;">        </span>writeStream<span style="font-weight:bold;color:#000000;">.</span>flush<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">catch</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>IOException<span style="color:#808080;"> </span>ex<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span>removeClient<span style="font-weight:bold;color:#000000;">(</span>ex<span style="font-weight:bold;color:#000000;">.</span>toString<span style="font-weight:bold;color:#000000;">(),</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">return</span><span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">      </span><span style="color:#007f00;font-size:9pt;">//Quit?</span>
<span style="color:#808080;">      </span>String<span style="font-weight:bold;color:#000000;">[]</span><span style="color:#808080;"> </span>segments<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>nextMsg<span style="font-weight:bold;color:#000000;">.</span>split<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">":"</span><span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">0</span><span style="font-weight:bold;color:#000000;">]==</span><span style="color:#7f007f;">"UDIS"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">&amp;&amp;</span><span style="color:#808080;"> </span>Integer<span style="font-weight:bold;color:#000000;">.</span>parseInt<span style="font-weight:bold;color:#000000;">(</span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">3</span><span style="font-weight:bold;color:#000000;">])==</span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">        </span>removeClient<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"Client requested disconnect."</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>

<span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">private</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">void</span><span style="color:#808080;"> </span>readLoop<span style="font-weight:bold;color:#000000;">()</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">( ; ; )</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">        </span><span style="color:#007f00;font-size:9pt;">//Read a message</span>
<span style="color:#808080;">        </span>String<span style="color:#808080;"> </span>message<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">""</span><span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">try</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">          </span>message<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>readStream<span style="font-weight:bold;color:#000000;">.</span>readLine<span style="font-weight:bold;color:#000000;">();</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">catch</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>IOException<span style="color:#808080;"> </span>ex<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">          </span><span style="color:#007f00;font-size:9pt;">//Close the server</span>
<span style="color:#808080;">          </span>removeClient<span style="font-weight:bold;color:#000000;">(</span>ex<span style="font-weight:bold;color:#000000;">.</span>toString<span style="font-weight:bold;color:#000000;">(),</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">break</span><span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">        </span><span style="color:#007f00;font-size:9pt;">//TEMP:Debug:</span>
<span style="color:#808080;">        </span>System<span style="font-weight:bold;color:#000000;">.</span>out<span style="font-weight:bold;color:#000000;">.</span>println<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"Read message: "</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>message<span style="font-weight:bold;color:#000000;">.</span>trim<span style="font-weight:bold;color:#000000;">());</span>

<span style="color:#808080;">        </span><span style="color:#007f00;font-size:9pt;">//Split</span>
<span style="color:#808080;">        </span>String<span style="font-weight:bold;color:#000000;">[]</span><span style="color:#808080;"> </span>segments<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>message<span style="font-weight:bold;color:#000000;">.</span>split<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">":"</span><span style="font-weight:bold;color:#000000;">);</span>

<span style="color:#808080;">        </span><span style="color:#007f00;font-size:9pt;">//React to the message</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">0</span><span style="font-weight:bold;color:#000000;">].</span>equals<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"CREQ"</span><span style="font-weight:bold;color:#000000;">))</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">//Connect Request</span>
<span style="color:#808080;">          </span><span style="color:#007f00;font-size:9pt;">//Save Avatar</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>avatarID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Integer<span style="font-weight:bold;color:#000000;">.</span>parseInt<span style="font-weight:bold;color:#000000;">(</span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">1</span><span style="font-weight:bold;color:#000000;">]);</span>

<span style="color:#808080;">          </span><span style="color:#007f00;font-size:9pt;">//Send this player a connect_response with his ID</span>
<span style="color:#808080;">          </span>String<span style="color:#808080;"> </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"CRES:"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>sendMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">          </span><span style="color:#007f00;font-size:9pt;">//Send this client's avatar ID to everyone ELSE</span>
<span style="color:#808080;">          </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"UCON:"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="color:#7f007f;">":"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>avatarID<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">synchronized</span><span style="font-weight:bold;color:#000000;">(</span>players<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>x<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">:</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>keySet<span style="font-weight:bold;color:#000000;">())</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">              </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">!=</span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">                </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>sendMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">          </span><span style="color:#007f00;font-size:9pt;">//Send to THIS player all previously-connected players.</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">synchronized</span><span style="font-weight:bold;color:#000000;">(</span>players<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>x<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">:</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>keySet<span style="font-weight:bold;color:#000000;">())</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">              </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">==</span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">||</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>avatarID<span style="font-weight:bold;color:#000000;">==</span><span style="color:#007f7f;">0</span><span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">//Might not have been initialized yet.</span>
<span style="color:#808080;">                </span><span style="font-weight:bold;color:#00007f;">continue</span><span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">              </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"UCON:"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="color:#7f007f;">":"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>avatarID<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">              </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>sendMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">else</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">0</span><span style="font-weight:bold;color:#000000;">].</span>equals<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"UDIS"</span><span style="font-weight:bold;color:#000000;">))</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">//(Request for) User Disconnect</span>
<span style="color:#808080;">          </span><span style="color:#007f00;font-size:9pt;">//Can only disconnect self</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>newid<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Integer<span style="font-weight:bold;color:#000000;">.</span>parseInt<span style="font-weight:bold;color:#000000;">(</span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">1</span><span style="font-weight:bold;color:#000000;">]);</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>newid<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">==</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">            </span><span style="color:#007f00;font-size:9pt;">//Send a disconnect message to this player</span>
<span style="color:#808080;">            </span><span style="color:#007f00;font-size:9pt;">// We close the connection after sending our own message</span>
<span style="color:#808080;">            </span>String<span style="color:#808080;"> </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"UDIS:"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>sendMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">      </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">    </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="font-weight:bold;color:#000000;">}</span></code></pre>
<p>At over 200 lines, the server code is somewhat long, but that&#8217;s usually what ends up happening with Java. Our server functions in a relatively simple manner. At first, there is only one thread, containing the ServerSocket. This is basically the “connection” class, which will constantly wait for connections from our clients. Each time a connection is detected, the main thread creates a small helper class with the socket it just opened. This class spawns two more threads, one for reading from the socket and the other for writing to it. Thus, the total number of threads on the server at any one time is equal to <span style="font-family:monospace;"><em>2 X number_of_clients + 1</em></span>. There are better ways of doing this (e.g., using the NIO library), but they would require us to modify our client (RPG Maker) code in ways that are somewhat difficult.</p>
<p>Anyway, once the server is running, each client thread simply reads and writes messages as one would expect. Because the code for our server is contained within one file, we can access most functions without requiring any Interfacing hacks. All in all, it&#8217;s a rather tiny server.</p>
<p>Compile your server (Ctrl+1 in TextPad), and then run it (Ctrl+2). It will use the default port (7689) on localhost (127.0.0.1). Open RPG Maker and run your game. Talk to the Network NPC and select the first connection (assuming you didn&#8217;t modify it). Switch back to the server window; hooray! you&#8217;re connected.</p>
<div id="attachment_267" class="wp-caption alignnone" style="width: 318px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_command_wnd.png"><img class="size-medium wp-image-267" title="post10_prot2_command_wnd" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_command_wnd.png?w=308&#038;h=176" alt="" width="308" height="176" /></a><p class="wp-caption-text">Our server window has messages from both players.</p></div>
<p>Run another game, and you&#8217;ll see your player there. Disconnect and connect as many clients as you like. However, for now I recommend disconnecting by <em><strong>closing </strong></em>the game client; for some reason, using the NPC to disconnect will occasionally crash the server. (This is undoubtedly a flaw in my server code, not a bug with networking in RPG Maker games.)</p>
<div id="attachment_269" class="wp-caption alignnone" style="width: 367px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_full_demo.png"><img class="size-medium wp-image-269" title="post10_prot2_full_demo" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_full_demo.png?w=357&#038;h=245" alt="" width="357" height="245" /></a><p class="wp-caption-text">Our NPCs connect, and they walk around randomly.</p></div>
<p>Everything works just fine; when you close the second window, its corresponding NPC will disappear from the first&#8217;s window. Isn&#8217;t that amazing?</p>
<p><strong><a style="text-decoration:none;color:green;" name="PostPart8">Game Prototype 3 &#8211; Chatting with Other Players</a></strong></p>
<p>We could stop here; our point has been proven. However, Step 2 was particularly time-consuming, and I don&#8217;t want you to think that network games are so tough. In fact, with the simple infrastructure we&#8217;ve developed for part 2, we can easily add the remaining functionality in a simple, modular way. (Of course, we&#8217;ll eventually reach the point where the network becomes saturated with messages. At that point, it will become <em><strong>very</strong></em> difficult to proceed, because we&#8217;ll have to start talking about interest management techniques.)</p>
<p>Let&#8217;s add client messages as a kind of “poor man&#8217;s chat” interface. Surprisingly, the networking is now the <em>easiest </em>part:</p>
<table style="border:1px solid black;" border="0" width="500">
<tbody>
<tr>
<td style="font-size:1.2em;font-family:monospace;"><strong><em>CHAT_MESSAGE</em></strong></td>
<td style="font-size:1em;"><em>Description</em></td>
</tr>
<tr>
<td style="background:gray;font-size:1em;" align="right" valign="top"><strong>Type</strong></td>
<td style="background:gray;font-size:1em;" valign="top">The string <strong>CMSG</strong></td>
</tr>
<tr>
<td style="font-size:1em;" align="right" valign="top">Player ID</td>
<td style="font-size:1em;" valign="top">The ID of the player sending the message.</td>
</tr>
<tr>
<td style="font-size:1em;" align="right" valign="top">Message</td>
<td style="font-size:1em;" valign="top">The message string.</td>
</tr>
</tbody>
</table>
<p>We will use the same network message to send a message request to the server, and to receive a message from the server (on behalf of another player). Add the following to <strong>Game_NetMessage</strong>:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>CHAT_MESSAGE
<span style="color:#808080;">    </span><span style="color:#7f007f;font-size:9pt;">"CMSG"</span><span style="color:#808080;"> </span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>And:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">self</span><span style="font-weight:bold;color:#000000;">.</span>Make_ChatMessage<span style="font-weight:bold;color:#000000;">(</span>playerNID<span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>msg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#7f007f;font-size:9pt;">"</span><span style="font-weight:bold;color:#000000;">#{</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>CHAT_MESSAGE<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;font-size:9pt;">:</span><span style="font-weight:bold;color:#000000;">#{</span>playerNID<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;font-size:9pt;">:</span><span style="font-weight:bold;color:#000000;">#{</span>msg<span style="font-weight:bold;color:#000000;">}</span><span style="color:#7f007f;font-size:9pt;">\n"</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>Add the following to <strong>Game_Network</strong>:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">sendChatMessage</span><span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#007f00;font-size:9pt;">#Note that this MIGHT occur if we haven't heard back from the server </span>
<span style="color:#808080;">    </span><span style="color:#007f00;font-size:9pt;"># yet. We might have to manually police this case later.</span>
<span style="color:#808080;">    </span>raise<span style="color:#808080;"> </span><span style="color:#7f007f;font-size:9pt;">"Cannot send message; you are not connected!"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">if</span><span style="color:#808080;"> </span><span style="color:#b00080;">@my_id</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">==</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#800000;">1</span>
<span style="color:#808080;">    </span>toSend<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>Make_ChatMessage<span style="font-weight:bold;color:#000000;">(</span><span style="color:#b00080;">@my_id</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span>msg<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span><span style="color:#800080;">$game_shared</span><span style="font-weight:bold;color:#000000;">.</span>queueClientMessage<span style="font-weight:bold;color:#000000;">(</span>toSend<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>Add the relevant message handling code to <strong>Game_Map</strong>, in the<strong> update_network</strong> function, right after the code for handling USER_DISCONNECT.</p>
<pre><code style="color:black;"><span style="color:#808080;">      </span><span style="font-weight:bold;color:#0000ef;">elsif</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">0</span><span style="font-weight:bold;color:#000000;">]==</span>Game_NetMessage<span style="font-weight:bold;color:#000000;">.</span>CHAT_MESSAGE
<span style="color:#808080;">        </span><span style="color:#007f00;font-size:9pt;">#Retrieve the message</span>
<span style="color:#808080;">        </span>cmsg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">2</span><span style="font-weight:bold;color:#000000;">]</span>

<span style="color:#808080;">        </span><span style="color:#007f00;font-size:9pt;">#Save the player's message</span>
<span style="color:#808080;">        </span>avtID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">].</span>to_i<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#808080;"> </span><span style="color:#800000;">1</span>
<span style="color:#808080;">        </span><span style="color:#b00080;">@events</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#b00080;">@net_npc_start</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>avtID<span style="font-weight:bold;color:#000000;">].</span>chat_message<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>cmsg

<span style="color:#808080;">        </span><span style="color:#007f00;font-size:9pt;">#Show an emotion icon</span>
<span style="color:#808080;">        </span><span style="color:#b00080;">@events</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#b00080;">@net_npc_start</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>avtID<span style="font-weight:bold;color:#000000;">].</span>balloon_id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800000;">1</span>
<span style="font-weight:bold;color:#0000ef;">      end</span><span style="color:#808080;">  </span></code></pre>
<p>This, of course, requires a new property to be added to <strong>Game_Event</strong>. Add the following to the <strong>Game_Event</strong> class, below the other <strong>attr_readers</strong></p>
<pre><code style="color:black;"><span style="color:#808080;">  </span>attr_accessor<span style="color:#808080;"> </span><span style="color:#c0a030;">:chat_message</span><span style="color:#808080;">             </span><span style="color:#007f00;font-size:9pt;"># Current message from other user</span></code></pre>
<p>&#8230;and in the <strong>initialize</strong> method:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#b00080;">@chat_message</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;font-size:9pt;">""</span></code></pre>
<p>Thus, each NPC now has a property, <strong>chat_message</strong>, which is updated whenever a network message of type CHAT_MESSAGE. From here, the code for the <strong>Show NPC Message</strong> Common Event should be obvious. First, hit F9 and go to the <strong>Actors </strong>tab. Press “Change Maximum&#8230;” and enter a number like 15. Then, name NPCs 10, 11, 12, and 13 to <strong>CurrNPCTxt Line 1</strong>, <strong>CurrNPCTxt Line 2</strong>, <strong>CurrNPCTxt Line 3</strong>, and <strong>CurrNPCTxt Line 4</strong>. Now, edit the <strong>Show NPC Message</strong> Common Event:</p>
<div id="attachment_273" class="wp-caption alignnone" style="width: 318px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_ce4.png"><img class="size-medium wp-image-273" title="post10_prot3_ce4" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_ce4.png?w=308&#038;h=450" alt="" width="308" height="450" /></a><p class="wp-caption-text">Despite its length; this common event is actually quite simplistic in nature.</p></div>
<p>This is one of those “exploding events” that PRG Maker famously espouses. Briefly described:</p>
<ul>
<li>We first run a simple script that takes the current NPCs <strong>chat_message</strong> and splits it whenever there&#8217;s a tab (\t). (We can&#8217;t split on newlines because newlines denote new messages in our network protocol.) The reason our script is so complex is so that we can handle cases such as the empty string (“no message”) or a string with less than 3 tabs (messages with less than 4 lines).
<pre><code style="color:black;"><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">#What NPC is talking? What's he saying?</span>
<span style="color:#808080;"> </span>currMsg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_map</span><span style="font-weight:bold;color:#000000;">.</span>chat<span style="font-weight:bold;color:#000000;"> </span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">9</span><span style="font-weight:bold;color:#000000;">]</span>

<span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">#Set NPCs 10..13 to be the lines of text</span>
<span style="color:#808080;"> </span>lines<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>currMsg<span style="font-weight:bold;color:#000000;">.</span>split<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;font-size:9pt;">"\t"</span><span style="font-weight:bold;color:#000000;">,</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#800000;">1</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;"> </span>rep<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>lines<span style="font-weight:bold;color:#000000;">.</span>empty?<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">?</span><span style="color:#808080;"> </span><span style="color:#800000;">4</span><span style="color:#808080;"> </span><span style="color:#c0a030;">:</span><span style="color:#808080;"> </span><span style="color:#800000;">4</span><span style="font-weight:bold;color:#000000;">-</span>lines<span style="font-weight:bold;color:#000000;">.</span>length
<span style="color:#808080;"> </span>lines<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+=</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#7f007f;font-size:9pt;">""</span><span style="font-weight:bold;color:#000000;">]*</span>rep
<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">for</span><span style="color:#808080;"> </span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">in</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span><span style="color:#800000;">0.</span><span style="font-weight:bold;color:#000000;">.</span><span style="color:#800000;">3</span><span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">  </span><span style="color:#800080;">$game_actors</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">10</span><span style="font-weight:bold;color:#000000;">+</span>id<span style="font-weight:bold;color:#000000;">].</span>name<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>lines<span style="font-weight:bold;color:#000000;">[</span>id<span style="font-weight:bold;color:#000000;">]</span>
<span style="color:#808080;"> </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
</li>
<li>Next, we run a much smaller script with sets the value of variable 8 (which you can rename to <strong>Curr NPC Avatar</strong>) to be equal to value of the avatar variable for the given NPC. I thought this kind of functionality was offered by RPG Maker&#8217;s standard events, but I couldn&#8217;t find it anywhere.
<pre><code style="color:black;"><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">#Set variable 8 to the current NPC's avatar</span>
<span style="color:#808080;"> </span>index<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">9</span><span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">-</span><span style="color:#808080;"> </span><span style="color:#800000;">6</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="color:#800000;">10</span>
<span style="color:#808080;"> </span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span><span style="color:#800000;">8</span><span style="font-weight:bold;color:#000000;">]</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#800080;">$game_variables</span><span style="font-weight:bold;color:#000000;">[</span>index<span style="font-weight:bold;color:#000000;">]</span></code></pre>
</li>
<li> Next, we have a big mess of <strong>If</strong> statements. Each “if” statement wraps the following text box command:
<pre><code style="color:black;">   \N[10]
   \N[11]
   \N[12]
   \N[13]</code></pre>
</li>
<li>&#8230;this uses the values we just stored in the Actors&#8217; names to spell our out message. The only difference between each text box in the if statements is their face picture; we change this based on the value of variable 8 (<strong>Curr NPC Avatar</strong>).</li>
</ul>
<p>The first script in our event will require the following method to be added to <strong>Game_Map</strong>:</p>
<pre><code style="color:black;"><span style="color:#808080;">  </span><span style="color:#007f00;">#Helper</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">def</span><span style="color:#808080;"> </span><span style="color:#007f7f;">chat</span><span style="font-weight:bold;color:#000000;">(</span>npcID<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">    </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#b00080;">@events</span><span style="font-weight:bold;color:#000000;">[</span>npcID<span style="font-weight:bold;color:#000000;">].</span>chat_message
<span style="color:#808080;">    </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">?</span><span style="color:#808080;"> </span>msg<span style="color:#808080;"> </span><span style="color:#c0a030;">:</span><span style="color:#808080;"> </span><span style="color:#7f007f;">""</span>
<span style="color:#808080;">  </span><span style="font-weight:bold;color:#0000ef;">end</span></code></pre>
<p>The name was kept short to prevent overflowing the tiny script box inside RPG Maker&#8217;s <strong>Script </strong>Event Command. The reason we check for nil values and replace them with the empty string is that some of the functions that call <strong>chat </strong>will expect strings to be returned.</p>
<p>So now, messages work –presuming that we can actually <em>send </em>one. The problem is, text entry in RPG Maker is notoriously obnoxious. We could use the “Hero Name” dialog to spell out the sentence word-by-word, and then display the partial sentence like we did with the IP dialog. This would be clumsy at best. We could provide a set of partial phrases, and allow the player to select lines 1 though 4. This would actually be a minor pain too. From the user&#8217;s point of view it would be simplest to make our own<strong> Scene_*</strong> class that traps key events and lets them just type out the sentence. But that could easily double the length of our simple prototype. Since the problem cannot be solved simplistically, I&#8217;ll just punt on it: we&#8217;ll give the player a set of four predefined messages. First, add the following event command to the end of Common Event 4, Show NPC Message:</p>
<pre><code style="color:black;">   Call Common Event 5</code></pre>
<p>Name Common Event 5 something like <strong>Respond to NPC</strong> and give it the following code:</p>
<div id="attachment_274" class="wp-caption alignnone" style="width: 372px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_ce5.png"><img class="size-medium wp-image-274" title="post10_prot3_ce5" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_ce5.png?w=362&#038;h=304" alt="" width="362" height="304" /></a><p class="wp-caption-text">Event that allows a player to communicate with everyone else.</p></div>
<p>This Common Event is easy to understand, although it is clearly a <strong>too cold</strong> type:</p>
<ul>
<li>Ask the player if he wants to respond to that NPC.</li>
<li>If so, let them choose a simple (one-line) message, a multi-line message, or just a glitchy message (to test what happens). I know, boring, huh?</li>
<li>Then, simply use the function we put in <strong>$game_network</strong> to send the message.
<pre><code style="color:black;"><span style="color:#808080;">  </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;font-size:9pt;">"Hi there, friend!"</span>
<span style="color:#808080;">  </span><span style="color:#800080;">$game_network</span><span style="font-weight:bold;color:#000000;">.</span>sendChatMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">)</span></code></pre>
</li>
</ul>
<p>Pretty simple, although I think it&#8217;s a bit of a bad abstraction (since we talk to a single NPC to change our message to all NPCs. But that&#8217;s a minor point; we could change this easily later if we wanted to. Anyway, all that&#8217;s left is our server code. In the function readLoop, add the following case:</p>
<pre><code style="color:black;"><span style="color:#808080;">        </span><span style="font-weight:bold;color:#000000;">}</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">else</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">0</span><span style="font-weight:bold;color:#000000;">].</span>equals<span style="font-weight:bold;color:#000000;">(</span><span style="color:#7f007f;">"CMSG"</span><span style="font-weight:bold;color:#000000;">))</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">//Send a chat message to all clients</span>
<span style="color:#808080;">          </span><span style="color:#007f00;font-size:9pt;">//Can only send messages from yourself</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>fromID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>Integer<span style="font-weight:bold;color:#000000;">.</span>parseInt<span style="font-weight:bold;color:#000000;">(</span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">1</span><span style="font-weight:bold;color:#000000;">]);</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>fromID<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">==</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">            </span><span style="color:#007f00;font-size:9pt;">//Send the same message to all other users</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#00007f;">synchronized</span><span style="font-weight:bold;color:#000000;">(</span>players<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">              </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>fromID<span style="font-weight:bold;color:#000000;">).</span>lastMsg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span>segments<span style="font-weight:bold;color:#000000;">[</span><span style="color:#007f7f;">2</span><span style="font-weight:bold;color:#000000;">];</span>
<span style="color:#808080;">              </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>x<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">:</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>keySet<span style="font-weight:bold;color:#000000;">())</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">                </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">!=</span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="font-weight:bold;color:#000000;">)</span>
<span style="color:#808080;">                  </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>sendMessage<span style="font-weight:bold;color:#000000;">(</span>message<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">              </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">        </span><span style="font-weight:bold;color:#000000;">}</span></code></pre>
<p>You&#8217;ll have to change the definition of <strong>GameConnection </strong>to include this “last known message” parameter:</p>
<pre><code style="color:black;"><span style="color:#808080;">    </span><span style="font-weight:bold;color:#00007f;">public</span><span style="color:#808080;"> </span>String<span style="color:#808080;"> </span>lastMsg<span style="font-weight:bold;color:#000000;">;</span></code></pre>
<p>&#8230;and, in the constructor:</p>
<pre><code style="color:black;"><span style="color:#808080;">      </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>lastMsg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">""</span><span style="font-weight:bold;color:#000000;">;</span></code></pre>
<p>You will, of course, need to add a similar broadcast to the <strong>UCON </strong>case. We can modify the last use of <strong>synchronized(players)</strong> to include this:</p>
<pre><code style="color:black;">
<span style="color:#808080;">          </span><span style="color:#007f00;font-size:9pt;">//Send to THIS player all previously-connected players and their messages</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#00007f;">synchronized</span><span style="font-weight:bold;color:#000000;">(</span>players<span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#00007f;">for</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span><span style="font-weight:bold;color:#00007f;">int</span><span style="color:#808080;"> </span>x<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">:</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>keySet<span style="font-weight:bold;color:#000000;">())</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">{</span>
<span style="color:#808080;">              </span><span style="font-weight:bold;color:#00007f;">if</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">==</span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">||</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>avatarID<span style="font-weight:bold;color:#000000;">==</span><span style="color:#007f7f;">0</span><span style="font-weight:bold;color:#000000;">)</span><span style="color:#808080;"> </span><span style="color:#007f00;font-size:9pt;">//Might not have been initialized yet.</span>
<span style="color:#808080;">                </span><span style="font-weight:bold;color:#00007f;">continue</span><span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">              </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"UCON:"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="color:#7f007f;">":"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>avatarID<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">              </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>sendMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">              </span>msg<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">=</span><span style="color:#808080;"> </span><span style="color:#7f007f;">"CMSG:"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>id<span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span><span style="color:#7f007f;">":"</span><span style="color:#808080;"> </span><span style="font-weight:bold;color:#000000;">+</span><span style="color:#808080;"> </span>players<span style="font-weight:bold;color:#000000;">.</span>get<span style="font-weight:bold;color:#000000;">(</span>x<span style="font-weight:bold;color:#000000;">).</span>lastMsg<span style="font-weight:bold;color:#000000;">;</span>
<span style="color:#808080;">              </span><span style="font-weight:bold;color:#00007f;">this</span><span style="font-weight:bold;color:#000000;">.</span>sendMessage<span style="font-weight:bold;color:#000000;">(</span>msg<span style="font-weight:bold;color:#000000;">);</span>
<span style="color:#808080;">            </span><span style="font-weight:bold;color:#000000;">}</span>
<span style="color:#808080;">          </span><span style="font-weight:bold;color:#000000;">}</span></code></pre>
<p>I&#8217;ve named this server <strong>VXServer2</strong>, and included its full listing in Code Segment 3, below, in case you&#8217;re not familiar enough with Java to insert the code yourself.</p>
<p><a href="http://lthzelda.files.wordpress.com/2010/04/segment3-java-file-vxserver2.odt">Code Segment 3</a> — Make sure this is in a file called VXServer2.java, or it won&#8217;t compile.</p>
<p>Anyway, compile it (Ctrl+1) and run it (Ctrl+2) then try out our nifty message code.</p>
<div id="attachment_275" class="wp-caption alignnone" style="width: 331px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_demo1.png"><img class="size-medium wp-image-275" title="post10_prot3_demo1" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_demo1.png?w=321&#038;h=260" alt="" width="321" height="260" /></a><p class="wp-caption-text">It looks like your friend has something to say to you.</p></div>
<p>The exclamation also appears at potentially inappropriate times, like when the NPC first logs on, but I don&#8217;t think that&#8217;s such a bad thing –it helps by alerting the player that a new NPC has connected.</p>
<div id="attachment_276" class="wp-caption alignnone" style="width: 361px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_demo2.png"><img class="size-medium wp-image-276" title="post10_prot3_demo2" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_demo2.png?w=351&#038;h=284" alt="" width="351" height="284" /></a><p class="wp-caption-text">A message which, if not user-defined, is at least user-chosen.</p></div>
<p>The server scales nicely, although if you&#8217;re running these examples locally, you&#8217;ll be limited by the fact that RPG Maker “pauses” all game windows except the currently-active one (so messages won&#8217;t be received). Nonetheless, the effect is impressive:</p>
<div id="attachment_277" class="wp-caption alignnone" style="width: 374px"><a href="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_demo3.png"><img class="size-medium wp-image-277" title="post10_prot3_demo3" src="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_demo3.png?w=364&#038;h=294" alt="" width="364" height="294" /></a><p class="wp-caption-text">Several NPCs; we are talking to one while another indicates that he has a new message for us. Pretty cool.</p></div>
<p><strong>Project</strong></p>
<p>For the first time, I&#8217;ve decided to release the final project&#8217;s code as a sample. Here&#8217;s a zip containing everything you&#8217;ll need; make sure you read the article to understand how it works. As always, all code is in the public domain, unless it is borrowed from another author (in which case I have noted it) and is thus released under the license chosen by the respective author. All such licenses are open-source in nature.</p>
<p>At the moment, I cannot find a good site to host the project file. However, I posted the sample code <a href="http://www.rpgmakervx.net/index.php?showtopic=30310"><span style="color:#0000ff;"><strong>on the RPG Maker VX Forums</strong></span></a>; you can download it from here (but you&#8217;ll need an account). If I can find a good hosting site, I&#8217;ll upload a direct link. Apologies for the inconvenience, readers (but it&#8217;s a nice forum anyway).</p>
<p><span style="color:#ff0000;"> </span></p>
<p><strong><a style="text-decoration:none;color:green;" name="PostPart9">Further Work</a></strong></p>
<p>I&#8217;m personally quite pleased with what we&#8217;ve accomplished; however, it&#8217;s by no means polished. There&#8217;s still bugs in the system, and there&#8217;s a great many improvements that could be made. Here&#8217;s some “homework” for you; I might get around to writing a post about one of these eventually, but for now I&#8217;m tired of writing server code.</p>
<ul>
<li>BUGFIX: Send a “glitch” message (option 3) and then try to read it with another player. Surprisingly, the client will crash! This was actually unintentional on my part, but it presents a nice, easy exercise for you. Figure out where the system is glitching up: server side, client side, or somewhere in between. Then fix it!</li>
<li>BUGFIX: For some reason, closing the network connection from the NPC might crash the server. Also, hitting “F12” to go back to the title screen might have a negative effect on the connection. Re-write parts of the server and client to be more robust at handling this type of thing.</li>
<li>FEATURE: Once connected, we should measure the average lag to the server, and print this in the lower-right corner of the screen. Perhaps use the <a href="http://lthzelda.wordpress.com/2009/02/07/rm-1-a-debug-window/"><span style="color:#0000ff;"><strong>Debug Window</strong></span></a> to design some kind of “connected” box which always hovers in the lower-right corner. Bonus points if you animate it with a spinning Internet icon.</li>
<li>FEATURE: Combine this article&#8217;s source with the <a href="http://lthzelda.wordpress.com/2009/06/05/rm-3-speech-balloons-that-%E2%80%9Ctype%E2%80%9D-their-message/"><span style="color:#0000ff;"><strong>NPC Talk Boxes</strong></span></a> one, and make NPC messages appear above their heads whenever they change. You can still show the exclamation emote when they first connect.</li>
<li>FEATURE: Our NPC code uses “sir” a lot, even if the connected player is clearly a female. Extend the game engine to handle strings like <strong>\sir</strong>, which expand into “sir” if the player is male and “ma&#8217;am” if the player is female.</li>
<li>FEATURE: Add user accounts and passwords, and do this in a way that keeps users&#8217; passwords safe and un-crackable –a salted hash comes to mind.</li>
<li>PROJECT: Allow players to fight each other. This isn&#8217;t as difficult as it seems, since RPG Maker&#8217;s battle system is turn-based. You can extend<strong> Scene_Battle</strong> to expect network input and wait until both teams have made their decisions. Then, you might add an icon to show if the other player is “ready”, “disconnected”, etc. Finally, you&#8217;ll have to take the opposing player&#8217;s “stats” and somehow turn them into monsters which you place on the opponent&#8217;s screen.</li>
<li>PROJECT: Assuming the previous project has been completed, add the ability for players to form “teams” and fight against each other at the party level. You can update your heads-up-display to show the moves your teammates have chosen, and you&#8217;ll probably want a team-chat and battle-chat feature (with real-time typing, not RPG Maker&#8217;s name entry dialogue). I&#8217;m giving this project a <span style="color:#b8860b;"><strong>gold star</strong></span>, since this is the project I would most like to do myself.</li>
<li>PROJECT: Extend our code to handle events arbitrarily. In other words, make it so that we can do something like <strong>$game_map.add_npc(Event(3, 5))</strong> to create a new NPC at location (3,5). This is harder than it sounds, and really only makes sense when preparing for the next item.</li>
<li>PROJECT: Track NPC movement in real-time. You might have to move our <strong>update_network</strong> code to a more prominent location –say, the place where RPG Maker handles user input. Regardless, the key challenge with this project is network congestion; sending 60 messages per NPC per second is a sure way to bog down your server. In other words, only update what&#8217;s necessary. You might, for example, send a USER_LEFT message when the player wants to move left. The server can then determine if moving left is allowed, and send back OK_TOGO_LEFT or NOGO_LEFT to inform the player. However, this will introduce some noticeable lag on the client side, so you might want to allow the client to begin moving left anyway, and just teleport him back if NOGO_LEFT was received. A careful consideration of when to attempt a move before receiving a response from the server is difficult, and will require extensive testing. On that note, you&#8217;ll have to test this code from multiple computers, since (1) there&#8217;s no lag otherwise and (2) RPG Maker pauses all but the top-most window. In fact, this pausing is a problem, since it interrupts the flow of messages. You&#8217;ll need to account for that somehow (perhaps force the game to remain full-screen? Or install a <a href="http://msdn.microsoft.com/en-us/library/ms997537.aspx"><span style="color:#0000ff;"><strong>Windows hook</strong></span></a> that tricks RPG Maker games into thinking they&#8217;re always a top-level window?). Either way, this project will easily take weeks of your time to get right.</li>
</ul>
<p>Happy coding!</p>
<p><strong>Update: Phoenix Demo</strong></p>
<p>Speed used the code in this post (along with tons of other cool scripts, including a mouse capture script!) to make a really awesome demo called Phoenix. <a href="http://www.rpgmakervx.net/index.php?showtopic=33168"><strong><span style="color:#0000ff;">Check it out here</span></strong></a>.<strong> </strong></p>
<p>Some screenshots:</p>
<div id="attachment_344" class="wp-caption alignnone" style="width: 228px"><strong><a href="http://lthzelda.files.wordpress.com/2010/04/my_chr.png"><img class="size-medium wp-image-344" title="my_chr" src="http://lthzelda.files.wordpress.com/2010/04/my_chr.png?w=218&#038;h=171" alt="" width="218" height="171" /></a></strong><p class="wp-caption-text">My character, loaded into the main game world.</p></div>
<div id="attachment_345" class="wp-caption alignnone" style="width: 236px"><a href="http://lthzelda.files.wordpress.com/2010/04/my_chr_2.png"><img class="size-medium wp-image-345" title="my_chr_2" src="http://lthzelda.files.wordpress.com/2010/04/my_chr_2.png?w=226&#038;h=177" alt="" width="226" height="177" /></a><p class="wp-caption-text">Loading of a second character, tracking down the first.</p></div>
<p>New features added by Speed include:</p>
<ul>
<li>Characters are tracked by x/y coordinates, and across various maps.</li>
<li>Full-featured chatting, account creation, password storage, etc. (He saves data in Text files).</li>
</ul>
<p>&#8230;plus a lot more. Pretty cool to see my code in action. And now, back to listening to <a href="http://ocremix.org/"><span style="color:#0000ff;"><strong>OC Remixes</strong></span></a>.</p>
<p><strong><br />
</strong></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/250/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/250/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/250/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/250/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/250/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/250/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/250/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/250/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/250/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/250/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/250/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/250/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/250/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/250/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=250&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2010/04/28/rm-4-tcp-sockets-in-rpg-maker-vx/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_first_crash.png?w=300" medium="image">
			<media:title type="html">post10_first_crash</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_conn_ref_err.png?w=300" medium="image">
			<media:title type="html">post10_conn_ref_err</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_javatextpad.png?w=300" medium="image">
			<media:title type="html">post10_javatextpad</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_server_ready.png?w=300" medium="image">
			<media:title type="html">post10_server_ready</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_server_works.png?w=300" medium="image">
			<media:title type="html">post10_server_works</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_server_log.png?w=300" medium="image">
			<media:title type="html">post10_server_log</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_starting_map.png?w=300" medium="image">
			<media:title type="html">post10_prot1_starting_map</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_heroes_added.png?w=300" medium="image">
			<media:title type="html">post10_prot1_heroes_added</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_selectnpc.png?w=300" medium="image">
			<media:title type="html">post10_prot1_selectnpc</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_setupautosave.png?w=300" medium="image">
			<media:title type="html">post10_prot1_setupautosave</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_testautosave.png?w=300" medium="image">
			<media:title type="html">post10_prot1_testautosave</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_home_map.png?w=300" medium="image">
			<media:title type="html">post10_prot1_home_map</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_npccore.png?w=300" medium="image">
			<media:title type="html">post10_prot1_npccore</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_ce1.png?w=300" medium="image">
			<media:title type="html">post10_prot1_ce1</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_ce2.png?w=300" medium="image">
			<media:title type="html">post10_prot1_ce2</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_ce3.png?w=300" medium="image">
			<media:title type="html">post10_prot1_ce3</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_partialip.png?w=300" medium="image">
			<media:title type="html">post10_prot1_partialip</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot1_savedip.png?w=300" medium="image">
			<media:title type="html">post10_prot1_savedip</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_mutextest.png?w=300" medium="image">
			<media:title type="html">post10_prot2_mutextest</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_newnpcs.png?w=300" medium="image">
			<media:title type="html">post10_prot2_newnpcs</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_npc1lastpage.png?w=300" medium="image">
			<media:title type="html">post10_prot2_npc1lastpage</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_disconnpc.png?w=300" medium="image">
			<media:title type="html">post10_prot2_disconnpc</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_command_wnd.png?w=300" medium="image">
			<media:title type="html">post10_prot2_command_wnd</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot2_full_demo.png?w=300" medium="image">
			<media:title type="html">post10_prot2_full_demo</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_ce4.png?w=205" medium="image">
			<media:title type="html">post10_prot3_ce4</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_ce5.png?w=300" medium="image">
			<media:title type="html">post10_prot3_ce5</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_demo1.png?w=300" medium="image">
			<media:title type="html">post10_prot3_demo1</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_demo2.png?w=300" medium="image">
			<media:title type="html">post10_prot3_demo2</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/post10_prot3_demo3.png?w=300" medium="image">
			<media:title type="html">post10_prot3_demo3</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/my_chr.png?w=300" medium="image">
			<media:title type="html">my_chr</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2010/04/my_chr_2.png?w=300" medium="image">
			<media:title type="html">my_chr_2</media:title>
		</media:content>
	</item>
		<item>
		<title>[EL-2] Eternal Lands Tray Notifier – Part 1</title>
		<link>http://lthzelda.wordpress.com/2009/11/03/el-2-eternal-lands-tray-notifier-%e2%80%93-part-1/</link>
		<comments>http://lthzelda.wordpress.com/2009/11/03/el-2-eternal-lands-tray-notifier-%e2%80%93-part-1/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 16:59:15 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=214</guid>
		<description><![CDATA[Blog Info: I finally did it: I took on a task that was too big for me to finish. Fortunately, I managed to get its basic functionality all done by press time. If you can follow along, you’ll know more &#8230; <a href="http://lthzelda.wordpress.com/2009/11/03/el-2-eternal-lands-tray-notifier-%e2%80%93-part-1/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=214&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em><strong>Blog Info:</strong> I finally did it: I took on a task that was too big for me to finish. Fortunately, I managed to get its basic functionality all done by press time. If you can follow along, you’ll know more than enough to continue on your own from here.</em></p>
<p><em><strong>Quick Note: </strong>I&#8217;m still trying to fix some of the formatting, but the content&#8217;s all here, so I decided just to post it. I&#8217;ll re-tab the untabbed code later. <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </em></p>
<p><em><strong>Back-story:</strong></em> Our <a href="http://lthzelda.wordpress.com/2009/04/11/el-1-game-event-notifier/"><strong><span style="color:#0000ff;">previous notifier</span></strong></a> was pretty hackneyed. It was also heavily coupled with the client program’s source, which might not be such a good idea. (What if the developer released the next version in Haskell or Forth? What if he closed the client source for the next release? What if —and this is the most likely— we don’t want to make our notifier any fancier using Win32 C++?) We need a new solution, and that means it’s time to pull out the big guns.</p>
<p><em><strong>Goal:</strong></em> Write a new notifier plugin. Make it operate external to the Eternal Lands program. Don’t slow down the client or the server. Don’t break any rules. Allow multiple types of notifications. Make it flashy.</p>
<p><strong>Licensing Notice</strong></p>
<p>This post provides a lot of code. While I normally provide all code in the public domain, I am restricting this post’s code with a license. Scroll to the bottom of the post to read it. This license is not for my benefit, but for the benefit of the EL servers and admins. Basically, it prohibits you from using this code to automate, or to modify it in any way that causes undue strain on the servers. You cannot inject events, nor can you delay sending them between the client and server. Finally, you cannot modify the thread priority of the event handler. The EL team has volunteered their time and creativity for your benefit, and I won’t have my code used to cause trouble for them.</p>
<p><strong>Step 1: General Approach</strong></p>
<p>Most of the problems in our last notifier stemmed from hastiness. In light of that, this section will take it slow and explain why we chose to do things the way we did. We’ll discuss some alternative approaches. But first, a general overview of what we want, and why our last plugin is no longer sufficient:</p>
<ul>
<li><strong>Event Notification</strong> — We want to see a message when something happens in Eternal Lands. Our initial program tagged harvest completion, but that was all. (Bonus question: How can you stop harvesting without displaying the “You stopped harvesting” message? It’s a tricky one… if you’re not sure, try harvesting some Seridium until you run out of Matter Essences.)</li>
<li><strong>Notification Timeliness</strong> — We want to show notifications only when necessary, and hide them when they’re not needed anymore. The previous plugin showed them if the Eternal Lands window was not the foreground window, and hid them when a new message came in. Later, we found this to be unsatisfactory. Better to hide all messages when the EL window gains focus.</li>
<li><strong>Variety of Notifications</strong> — Seeing a non-descript “You stopped harvesting” is different from seeing a shiny “You found an Enrichment Stone!” or a red “You have died and gone to the underworld”. We’ll add multiple types of notifications, which will necessitate allowing them to stack, fade in, and fade out. If you guessed that we won’t be doing all this graphical work in Win32 C++, you guessed right!</li>
<li><strong>Separation from Client Code</strong> — We won’t be using C++, nor will we be building directly on top of the Eternal Lands source. Rather, we’ll build a separate module that will load the EL client, and then filter all messages sent to it. We also want a system tray icon, and we might even consider removing the Eternal Lands window from the taskbar entirely.</li>
<li><strong>Fast and Extensible</strong> — We want the code to be fast (sorry, Perl). We want it to be easy to add new filters (sorry, C). We want it to operate directly on the network data (sorry, Forth) and have a great graphics library. If it’s native to Windows, all the better. Our choice is C#.</li>
</ul>
<p><span style="color:#008000;"><strong>Why not just read the client log file?</strong></span> If you browse to “C:\Users\<strong>User Name</strong>\Documents\Eternal Lands\main\chat_log.txt” —possibly replacing “main” with the name of the server you plan on, and “Documents” with “My Documents” on Windows 7— you’ll find a nice log of (most of) the chat window. Fiddle a bit more, and you’ll find that it’s updated in real time. Why, then, do we not simply <strong>tail </strong>this file? In Windows, this is pretty easy to do in Java:</p>
<pre><code style="color:black;"><span style="color:#0000ff;">public void</span> run<span style="color:#ff0000;">() {</span>
  <span style="color:#000080;">File </span>f = <span style="color:#0000ff;">new </span><span style="color:#000080;">File</span><span style="color:#ff0000;">(</span><span style="color:#008080;">"C:\\ ... \\chat_long.txt"</span><span style="color:#ff0000;">)</span>;
  <span style="color:#0000ff;">long </span>fPointer = ;<span style="color:#008000;">/* Seek to the end of the file */</span>
  <span style="color:#0000ff;">for </span><span style="color:#ff0000;">(</span>;;<span style="color:#ff0000;">) {</span>
    <span style="color:#000080;">Thread</span>.sleep<span style="color:#ff0000;">(</span>100<span style="color:#ff0000;">)</span>;
    <span style="color:#0000ff;">long </span>len = f.length<span style="color:#ff0000;">()</span>;
    <span style="color:#0000ff;">if </span><span style="color:#ff0000;">(</span>len &lt; fPointer<span style="color:#ff0000;">)</span>  <span style="color:#008000;">//Log was reset</span>
      fPointer = len;
    <span style="color:#0000ff;">else if</span> <span style="color:#ff0000;">(</span>len &gt; fPointer<span style="color:#ff0000;">) {</span> <span style="color:#008000;">//File was appended to</span>
      <span style="color:#000080;">RandomAccessFile </span>raf = <span style="color:#0000ff;">new </span><span style="color:#000080;">RandomAccessFile</span><span style="color:#ff0000;">(</span>f, <span style="color:#339966;">"r"</span><span style="color:#ff0000;">)</span>;
      raf.seek<span style="color:#ff0000;">(</span>fPointer<span style="color:#ff0000;">)</span>;
<span style="color:#000080;">      String <span style="color:#000000;">line</span></span><span style="color:#000000;"> </span>= <span style="color:#0000ff;">null</span>;
      <span style="color:#0000ff;">while </span><span style="color:#ff0000;">((</span>line = raf.readLine<span style="color:#ff0000;">())</span> != <span style="color:#0000ff;">null</span><span style="color:#ff0000;">)</span>
      processMessage<span style="color:#ff0000;">(</span>line<span style="color:#ff0000;">)</span>;
      fPointer = raf.getFilePointer<span style="color:#ff0000;">()</span>;
      raf.close<span style="color:#ff0000;">()</span>;
<span style="color:#ff0000;">    }
  }
}</span></code></pre>
<p>Don’t use this code; it doesn’t check for exceptions, and it isn’t mine (it’s part of the <strong><span style="color:#0000ff;">java-tail</span></strong> project). More importantly, it doesn’t really work if the file is being constantly added to. You could re-read the file after exceptions, but then you’re entering into the messy possibility of reading the same line twice.</p>
<p>On a totally different level, this is sub-optimal because the client log doesn’t contain everything. What if you wanted to write a filter that tells you if you’ve been interrupted from harvesting by a PKer instead of a sub-lethal cave-in? Battles don’t send messages to the console, unless you die. Wouldn’t you rather find out while you still have a fighting chance?</p>
<p><strong>Why not use Java?</strong> This question applies to any other language, but I feel the most reasonable alternative is Java. (I consider Visual Basic .NET to be identical to C# for all such discussions, by the way.) Java is a very good language, and there is no reason not to use it. Your favorite language is also probably a good choice, although I might not have heard of it. My reason for choosing C# was that, of all the candidates I considered, it was capable of (read: “I knew how to use it to”) solving all the sub-tasks I needed. Feel free to follow along in Python or Ruby or Tcl/Tk, converting the code as you like. Ooh, or Delphi; I like Delphi. Regardless, I’m doing this in C#, and any intermediate programmer should be able to follow along.</p>
<p><strong>Why not patch the client code?</strong> My earlier reasons for not simply extending on our <a href="http://lthzelda.wordpress.com/2009/04/11/el-1-game-event-notifier/"><strong><span style="color:#0000ff;">earlier project</span></strong></a> were true, but also somewhat motivation by the fact that I knew I was going to use a much higher-level (and thus incompatible) language from the start. What if you started this project using C++? In that case, I’d still encourage you to keep your code totally separate. Besides all the previously-listed reasons, here’s one more: bugs. If you’re recompiling the entire Eternal Lands code base with each new notification, then you’re bound to slip up from time to time. This is part of development; you can release bug-free software, but your internal builds will be fraught with bugs. Now, given the nature of bugs in C++, this means that your code could easily corrupt some of <a href="http://eternal-lands.blogspot.com/"><strong><span style="color:#0000ff;">Entropy</span></strong></a>’s code. If this results in sending a million messages a second to the server, “ya might get banned”. That said, if your bug is passive, and other people use your plugin, you start to run a real risk of bringing down the server. And even if your bug is harmless, it will still confuse developers trying to nail it down. Trust me when I say that tracking a bug to third-party patches does <em><strong>not</strong></em> make developers happy.</p>
<p><strong>How will we catch messages?</strong> We’ll start our program first, which should give it priority over any child processes and their system resources. Then, we’ll connect our program to the Eternal Lands server, and connect the EL Client to our program (by adding a new server to the config file). Finally, as we ferry messages between client and server, we’ll send them off to a separate, low-priority thread where we can match then against an arbitrary number of filters, spawning pop-up windows as we identify messages of interest.</p>
<p><strong>Step 2: Connecting to the client</strong></p>
<p>The first thing we need to do it connect to the server. From the Eternal Lands server config file (D:\Programs\Eternal Lands\servers.lst), we know that the “main” server connects to port <strong>2000 </strong>on <strong>game.eternal-lands.com</strong>. Open up Visual Studio (the free <a href="http://www.microsoft.com/express/vcsharp/"><span style="color:#0000ff;"><strong>Express Edition for C#</strong></span></a> is pretty nice) and start a new project. Make it a “Windows Forms Application”. You’ll be presented with the design view for “Form1.cs”. In case you aren’t familiar with Visual Studio, take a minute to note the toolbox (circled in red on the left) and the Solution explorer on the right. Right click on Form1.cs in the solution explorer and note the two options shown circled in blue. “View Designer” will bring up the form designer, like you see now. “View Code” will bring up the code that runs everything behind the scenes. Note that C# supports “partial” classes, so the “View Code” option will <em><strong>not </strong></em>show you any code generated by Visual Studio, unless you are running a very, very old version of Visual Studio.</p>
<div id="attachment_220" class="wp-caption alignnone" style="width: 237px"><a href="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_quick_vcs_intro.png"><img title="post_9_pt1_quick_vcs_intro" src="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_quick_vcs_intro.png?w=227&#038;h=147" alt="Visual Studio's &quot;Hiding Tool Bars&quot;" width="227" height="147" /></a><p class="wp-caption-text">Visual Studio&#39;s &quot;Hiding Tool Bars&quot;</p></div>
<p>Open the toolbox (by clicking on it) and drag a “Text Box” control onto your Form. (This is under the “Common Controls” group). Now, right-click on this box and choose “Properties”. The most important property is called “(Name)”, because this is what we’ll use to identify the control in our C# code. The following table details which controls to add, and what properties to set for them. All other properties can be left at their defaults, or you can change them to your liking. For example, you might change the “font” for your controls, or the “BorderStyle”. Go for it.</p>
<table style="font-family:courier;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td style="background-color:#8be;" colspan="2"><strong>TextBox</strong>*</td>
</tr>
<tr>
<td>(Name)</td>
<td>txtPathToELFolder</td>
</tr>
<tr>
<td>Text</td>
<td>C:\Program Files\Eternal Lands</td>
</tr>
</tbody>
</table>
<p><em>*Note: If you installed Eternal Lands to a different location, set the <strong>Text </strong>property accordingly. Escaped backslashes are not necessary when entering this string in the visual editor.</em></p>
<table style="font-family:courier;margin-bottom:15px;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td style="background-color:#8be;" colspan="2"><strong>Button</strong></td>
</tr>
<tr>
<td>(Name)</td>
<td>btnRead</td>
</tr>
<tr>
<td>Text</td>
<td>Read</td>
</tr>
</tbody>
</table>
<table style="font-family:courier;margin-bottom:15px;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td style="background-color:#8be;" colspan="2"><strong>ComboBox</strong></td>
</tr>
<tr>
<td>(Name)</td>
<td>cmbServers</td>
</tr>
<tr>
<td>Enabled</td>
<td>False</td>
</tr>
</tbody>
</table>
<table style="font-family:courier;margin-bottom:15px;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td style="background-color:#8be;" colspan="2"><strong>Button</strong></td>
</tr>
<tr>
<td>(Name)</td>
<td>btnConnect</td>
</tr>
<tr>
<td>Text</td>
<td>Connect</td>
</tr>
<tr>
<td>Enabled</td>
<td>False</td>
</tr>
</tbody>
</table>
<table style="font-family:courier;margin-bottom:15px;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td style="background-color:#8be;" colspan="2"><strong>Label</strong></td>
</tr>
<tr>
<td>(Name)</td>
<td>lblZero</td>
</tr>
<tr>
<td>Text</td>
<td>0</td>
</tr>
<tr>
<td>TextAlign</td>
<td>MiddleRight</td>
</tr>
<tr>
<td>Font</td>
<td>Courier New, 14.25pt, style=Bold</td>
</tr>
<tr>
<td>ForeColor</td>
<td>DarkRed</td>
</tr>
<tr>
<td>AutoSize</td>
<td>False</td>
</tr>
<tr>
<td>Size</td>
<td>346, 399</td>
</tr>
</tbody>
</table>
<table style="font-family:courier;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td style="background-color:#8be;" colspan="2"><strong>TextBox</strong></td>
</tr>
<tr>
<td>(Name)</td>
<td>txtConsole</td>
</tr>
<tr>
<td>ReadOnly</td>
<td>True</td>
</tr>
<tr>
<td>Multiline</td>
<td>True</td>
</tr>
<tr>
<td>Size</td>
<td>306, 188</td>
</tr>
</tbody>
</table>
<p>Arrange these components like so:</p>
<div id="attachment_218" class="wp-caption alignnone" style="width: 213px"><a href="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_initial_component_layout.png"><img title="post_9_pt1_initial_component_layout" src="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_initial_component_layout.png?w=203&#038;h=148" alt="Line Up Your Components Roughly Like This" width="203" height="148" /></a><p class="wp-caption-text">Line Up Your Components Roughly Like This</p></div>
<p><strong>A quick note on <a href="http://en.wikipedia.org/wiki/Hungarian_notation"><span style="color:#0000ff;">Hungarian Notation</span></a>:</strong> in general, I do not support this hackneyed way of naming variables, especially in a strongly-typed language like C#. However, for GUI components, I often find myself saying “Ah, what <em>was </em>the name of that button I wanted?” By naming controls in an ordered fashion, I can type <strong>btn&lt;Space&gt;</strong> and get some help from Visual Studio’s auto-complete feature. Having large numbers of (essentially) global variables for your form controls is unavoidable in C#, and I find this approach scales really well, despite the frown that most people get when they see Hungarian Notation.</p>
<p>Compile your program (<strong>Build &#8211;&gt; Build Solution</strong>) and then run it (<strong>Debug &#8211;&gt; Start Without Debugging</strong>). None of the software logic is hooked up yet, but the general idea is that the user can change the client directory, then click “Read” to read the list of available servers. Next, the user can choose a server to connect to from the combo box, and click “Connect”. Log messages will be shown in our multi-line Text Box control, and the mysterious “Zero Count” will be used for something which will be explained later. Well, let’s start the magic.</p>
<p>Click on the “Read” button, and go to its properties. Notice that little lightning bolt, circled below in red? If you click that, you will switch to “Event” triggers. Click the button left of it to go back to properties view.</p>
<div id="attachment_216" class="wp-caption alignnone" style="width: 232px"><a href="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_event_triggers_button.png"><img title="post_9_pt1_event_triggers_button" src="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_event_triggers_button.png?w=222&#038;h=162" alt="Bad Design Puts This Very Important Button in a Very Obscure Place." width="222" height="162" /></a><p class="wp-caption-text">Bad Design Puts This Very Important Button in a Very Obscure Place.</p></div>
<p>Click the event button, find the event called <strong>Click</strong>, and type “ReadELFiles” in the box. Then, press “Enter”. Visual Studio will bring you to Form1.cs’s <strong>Code View</strong>, with a skeleton implementation of the <strong>ReadELFiles </strong>function used for your <strong>Click </strong>event delegate. Java users will be saying “What?”, as delegates and events make little sense from a minimalist point of view. We’ll have a good example of the power of delegates later.</p>
<p>Here’s the implementation of <strong>ReadELFiles</strong>:</p>
<pre><span style="font-size:10pt;">private</span><span style="font-size:10pt;"> <span style="color:blue;">void</span> ReadELFiles(<span style="color:blue;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</span>
<span style="font-size:10pt;">{</span>
  <span style="font-size:10pt;"><span style="color:green;">//Reload an entirely new list of servers.</span></span>
  <span style="font-size:10pt;">cmbServers.Items.Clear();</span>

  <span style="font-size:10pt;"><span style="color:green;">//Don’t load anything if we specified an invalid directory.</span></span>
  <span style="font-size:10pt;"><span style="color:blue;">if</span> (!<span style="color:#2b91af;">File</span>.Exists(txtPathToELFolder.Text + <span style="color:#a31515;">"\\"</span> + <span style="color:#a31515;">"el.exe"</span>))</span>
  <span style="font-size:10pt;">{</span>
    <span style="font-size:10pt;">txtConsole.Text = <span style="color:#a31515;">"Error: el.exe doesn't exist in EL folder"</span>;</span>
    <span style="font-size:10pt;"><span style="color:blue;">return</span>;</span>
  <span style="font-size:10pt;">}</span>
  <span style="font-size:10pt;"><span style="color:blue;">else</span> <span style="color:blue;">if</span> (!<span style="color:#2b91af;">File</span>.Exists(txtPathToELFolder.Text + <span style="color:#a31515;">"\\"</span> + <span style="color:#a31515;">"servers.lst"</span>))</span>
  <span style="font-size:10pt;">{</span>
<span style="font-size:10pt;">    txtConsole.Text = <span style="color:#a31515;">"Error: servers.lst doesn't exist in EL folder"</span>;</span>
    <span style="font-size:10pt;"><span style="color:blue;">return</span>;</span>
  <span style="font-size:10pt;">}</span>

  <span style="font-size:10pt;"><span style="color:green;">//Open our servers file and read it.</span></span>
  <span style="font-size:10pt;"><span style="color:blue;">bool</span> foundLoopback = <span style="color:blue;">false</span>;</span>
  <span style="font-size:10pt;"><span style="color:#2b91af;">StreamReader</span> srvFile = <span style="color:blue;">new</span> <span style="color:#2b91af;">StreamReader</span>(txtPathToELFolder.Text + <span style="color:#a31515;">"\\"</span> + <span style="color:#a31515;">"servers.lst"</span>);</span>
  <span style="font-size:10pt;"><span style="color:blue;">while</span> (!srvFile.EndOfStream)</span>
  <span style="font-size:10pt;">{</span>
    <span style="font-size:10pt;"><span style="color:#2b91af;">String</span> line = srvFile.ReadLine();</span>
    <span style="font-size:10pt;"><span style="color:blue;">if</span> (line == <span style="color:blue;">null</span>)</span>
      <span style="font-size:10pt;"><span style="color:blue;">break</span>;</span>

    <span style="font-size:10pt;"><span style="color:green;">//Coment? Empty?</span></span>
<span style="font-size:10pt;">    line = line.Trim();</span>
    <span style="font-size:10pt;"><span style="color:blue;">if</span> (line.StartsWith(<span style="color:#a31515;">"#"</span>) || line.Length == 0)</span>
      <span style="font-size:10pt;"><span style="color:blue;">continue</span>;</span>

<span style="font-size:10pt;"><span style="color:green;">    //Read:</span></span>
<span style="font-size:10pt;"><span style="color:green;">    //ID, Config_Dir, Address, Port, Description</span></span>
    <span style="font-size:10pt;"><span style="color:#2b91af;">String</span> regex = <span style="color:#a31515;">"([^ \t]+)[ \t]+([^ \t]*)[ \t]+([^ \t]*)[ \t]+([^ \t]*)[ \t]+(.*)"</span>;</span>
    <span style="font-size:10pt;"><span style="color:#2b91af;">Match</span> m = <span style="color:#2b91af;">Regex</span>.Match(line, regex);</span>
    <span style="font-size:10pt;"><span style="color:#2b91af;">ServerInfo</span> sInf = <span style="color:blue;">new</span><span style="color:#2b91af;"> ServerInfo</span>();</span>
    <span style="font-size:10pt;"><span style="color:blue;">if</span> (m.Success &amp;&amp; m.Groups.Count == 6)</span>
    <span style="font-size:10pt;">{</span>
      <span style="font-size:10pt;">sInf.id = m.Groups[1].Value;</span>
      <span style="font-size:10pt;"><span style="color:blue;">if</span> (sInf.id.Equals(<span style="color:#a31515;">"loopback"</span>))</span>
        <span style="font-size:10pt;">foundLoopback = <span style="color:blue;">true</span>;</span>
      <span style="font-size:10pt;">sInf.configDir = m.Groups[2].Value;</span>
      <span style="font-size:10pt;">sInf.address = m.Groups[3].Value;</span>
      <span style="font-size:10pt;"><span style="color:blue;">try</span></span>
      <span style="font-size:10pt;">{</span>
        <span style="font-size:10pt;">sInf.port = <span style="color:#2b91af;">Int32</span>.Parse(m.Groups[4].Value);</span>
      <span style="font-size:10pt;">}</span>
      <span style="font-size:10pt;"><span style="color:blue;">catch</span> (<span style="color:#2b91af;">FormatException</span>)</span>
      <span style="font-size:10pt;">{</span>
        <span style="font-size:10pt;"><span style="color:green;">//Don't add</span></span>
        <span style="font-size:10pt;"><span style="color:blue;">continue</span>;</span>
      <span style="font-size:10pt;">}</span>
      <span style="font-size:10pt;">sInf.description = m.Groups[5].Value;</span>
      <span style="font-size:10pt;">cmbServers.Items.Add(sInf);</span>

       <span style="font-size:10pt;"><span style="color:green;">//Loopback?</span></span>
      <span style="font-size:10pt;"><span style="color:blue;">if</span> (sInf.id.Equals(<span style="color:#a31515;">"loopback"</span>))</span>
        <span style="font-size:10pt;">loopbackInfo = sInf;</span>
    <span style="font-size:10pt;">}</span>
  <span style="font-size:10pt;">}</span>
  <span style="font-size:10pt;">srvFile.Close();</span>
<span style="font-size:10pt;">
<span style="color:green;">  //Do we need to add our own local server?</span></span>
  <span style="font-size:10pt;"><span style="color:blue;">if</span> (!foundLoopback)</span>
  <span style="font-size:10pt;">{</span>
    <span style="font-size:10pt;"><span style="color:green;">//Copy existing server file</span></span>
    <span style="font-size:10pt;"><span style="color:#2b91af;">StreamReader</span> inFile = <span style="color:blue;">new</span> <span style="color:#2b91af;">StreamReader</span>(txtPathToELFolder.Text + <span style="color:#a31515;">"\\"</span> + <span style="color:#a31515;">"servers.lst"</span>);</span>
    <span style="font-size:10pt;"><span style="color:#2b91af;">StreamWriter</span> outFile = <span style="color:blue;">new</span> <span style="color:#2b91af;">StreamWriter</span>(txtPathToELFolder.Text + <span style="color:#a31515;">"\\"</span> + <span style="color:#a31515;">"servers.lst.new"</span>);</span>
    <span style="font-size:10pt;"><span style="color:blue;">for</span> (<span style="color:#2b91af;">String</span> line = inFile.ReadLine(); line != <span style="color:blue;">null</span>; line = inFile.ReadLine())</span>
      <span style="font-size:10pt;">outFile.WriteLine(line);</span>
    <span style="font-size:10pt;">inFile.Close();</span>
<span style="font-size:10pt;">
<span style="color:green;">    //Add our own category</span></span>
    <span style="font-size:10pt;">outFile.WriteLine(srvLine);</span>
<span style="font-size:10pt;">
<span style="color:green;">    //Close, swap, notify.</span></span>
    <span style="font-size:10pt;">outFile.Close();</span>
    <span style="font-size:10pt;"><span style="color:#2b91af;">File</span>.Delete(txtPathToELFolder.Text + <span style="color:#a31515;">"\\"</span> + <span style="color:#a31515;">"servers.lst"</span>);</span>
    <span style="font-size:10pt;"><span style="color:#2b91af;">File</span>.Move(txtPathToELFolder.Text + <span style="color:#a31515;">"\\"</span> + <span style="color:#a31515;">"servers.lst.new"</span>, txtPathToELFolder.Text + <span style="color:#a31515;">"\\"</span> + <span style="color:#a31515;">"servers.lst"</span>);</span>
    <span style="font-size:10pt;">ShowConnectMsg(<span style="color:#a31515;">"Created loopback entry."</span>);</span>
<span style="font-size:10pt;">
<span style="color:green;">    //Add a new item to the list</span></span>
    <span style="font-size:10pt;">loopbackInfo = <span style="color:blue;">new</span> <span style="color:#2b91af;">ServerInfo</span>();</span>
    <span style="font-size:10pt;">loopbackInfo.id = <span style="color:#a31515;">"loopback"</span>;</span>
    <span style="font-size:10pt;">loopbackInfo.configDir = <span style="color:#a31515;">"main"</span>;</span>
    <span style="font-size:10pt;">loopbackInfo.address = SERVER_ADDR;</span>
    <span style="font-size:10pt;">loopbackInfo.port = SERVER_PORT;</span>
    <span style="font-size:10pt;">cmbServers.Items.Add(loopbackInfo);</span>
  <span style="font-size:10pt;">}</span>
<span style="font-size:10pt;">
<span style="color:blue;">  if</span> (cmbServers.Items.Count &gt; 0)</span>
    <span style="font-size:10pt;">cmbServers.SelectedIndex = 0;</span>
}</pre>
<p>Make sure you add the following <a href="http://msdn.microsoft.com/en-us/library/sf0df423%28VS.80%29.aspx"><strong><span style="color:#0000ff;">using directives</span></strong></a> to the top of Form1.cs, otherwise you’ll get errors stating that “The name &lt;something&gt; does not exist in the current context”. You also won’t get auto-complete functionality until the proper directives are added. (Auto-imports is something I miss dreadfully from Eclipse.)</p>
<pre><span style="font-size:10pt;"><span style="color:blue;">  using</span> System.Text.RegularExpressions;</span>
<span style="font-size:10pt;"><span style="color:blue;">  using</span> System.IO;</span></pre>
<p>You will also need the following variables; add them as part of the class (e.g., one line after the opening brace following “public partial class Form1 : Form”)</p>
<pre><span style="font-size:10pt;"><span style="color:blue;">public const string</span> SERVER_ADDR = <span style="color:#a31515;">"127.0.0.1";</span>
</span><span style="font-size:10pt;"><span style="color:blue;">public const string</span> SERVER_PORT = 5421;
</span><span style="font-size:10pt;"><span style="color:blue;">private string</span> srvLine = <span style="color:#a31515;">"127.0.0.1";"loopback        main            "</span> + SERVER_ADDR
      + <span style="color:#a31515;">"               "</span> + SERVER_PORT + <span style="color:#a31515;">"    Loopback adapter for use with the EL Notifier"</span>;
</span><span style="font-size:10pt;"><span style="color:blue;">private</span> ServerInfo loopbackInfo;
</span></pre>
<p>We also need this “ServerInfo” structure everyone’s been talking about. Add it as part of the namespace (<strong>not </strong>the class Form1).</p>
<pre><span style="font-size:10pt;font-family:&amp;">public</span><span style="font-size:10pt;font-family:&amp;"> <span style="color:blue;">struct</span> <span style="color:#2b91af;">ServerInfo</span></span>
<span style="font-size:10pt;font-family:&amp;">{</span>
<span style="font-size:10pt;font-family:&amp;"><span style="color:blue;">  public</span> <span style="color:#2b91af;">String</span> id;</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  public</span> <span style="color:#2b91af;">String</span> configDir;</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  public</span> <span style="color:#2b91af;">String</span> address;</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  public</span> <span style="color:blue;">int</span> port;</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  public</span> <span style="color:#2b91af;">String</span> description;</span>
<span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  public</span> <span style="color:blue;">override</span><span style="color:#2b91af;"> String</span> ToString()</span><span style="font-size:10pt;font-family:&amp;">
  {</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">    return</span> description;</span><span style="font-size:10pt;font-family:&amp;">
  }</span>
}</pre>
<p>The “ToString()” method is called by the Combo Box control to display the Object it contains; overriding it allows us to dictate that ServerInfo items are displayed by the description. There are better (but less concise) ways of controlling Combo Box output.</p>
<p>Note that structs in C# are very different than structs in C++. Indeed, you could have used a class here; the only difference would have been in its copy semantics, and possibly its memory footprint.</p>
<p>The only thing you’re missing is the <strong>ShowConnectMsg </strong>delegate, but for now just assume it’s a standard function call that does some non-essential logging. Let’s dissect the code we just wrote!</p>
<p>The <strong>SERVER_ADDR</strong> and <strong>SERVER_PORT</strong> variables help us to set up our program as a middleware between the EL Client and the EL Server. Our program has both client and server aspects; these two variables define access to the latter. We use <strong>srvLine </strong>to shim the servers list so that it can access our “Loopback” interface. Note that <strong>srvLine </strong>is effectively constant, even though it is not declared that way.</p>
<p>We are basically equivocating on the program’s socket expectations. From Wikipedia:</p>
<blockquote><p>An Internet socket is characterized by a unique combination of the following:</p>
<ul>
<li>Protocol (TCP, UDP or raw IP).</li>
<li>Local socket address (Local IP address and port number)</li>
<li>Remote socket address (Only for established TCP sockets.)</li>
</ul>
</blockquote>
<p>The original connection from EL Client to EL Server has one socket: a TCP-enabled connection from 127.0.0.1:???? to game.eternal-lands.com:2000. This socket is bi-directional. We don’t know the local port, because local ports are almost always randomly assigned. We don’t technically know the server port either, but 2000 is what we connect to, so I’ll list that here.</p>
<p>Our shimmed middleware creates two bi-directional sockets:</p>
<p><code style="color:black;">TCP, 127.0.0.1:???? ? SERVER_ADDR:SERVER_PORT<br />
TCP, SERVER_ADDR:???? ? game.eternal-lands.com:2000</code></p>
<p>Note that, as per the usual, we don’t know the local ports. Either way, we are guaranteed that they will be unique.</p>
<p>All that explanation for just three lines of code? Well, if you’re a non-network guy like me, figuring this out is one of the hardest parts of this project. Now, on to the rest of the code:</p>
<p>The <strong>ReadELFiles </strong>function is pretty easy to follow:</p>
<ul>
<li>Note that the function parameters “sender” and “e” are not used in our function. These are mandated by the .NET platform, but are not needed for our simple example.</li>
<li>The <strong>foundLoopback </strong>variable is used to check each line read from servers.lst. If the id of that line is “loopback”, then we know a loopback entry exists. If, at the end of scanning, no such entry was found, we just add it to the end of the file. That way, when we start Eternal Lands, we can connect to the <strong>loopback </strong>server (instead of <strong>main </strong>or <strong>pk </strong>or <strong>testing</strong>) and fool the client into thinking it’s connecting to the real server, instead of our fake, localhost middleware.</li>
<li>Note that we <em><strong>should </strong></em>check the <strong>loopback </strong>entry to ensure that its <strong>address </strong>and <strong>port </strong>parameters match ours. I’ll leave this as an exercise in regular expressions.</li>
<li>Some <strong><a href="http://en.wikipedia.org/wiki/Pattern_matching"><span style="color:#0000ff;">regex</span></a> </strong>pattern matching is used to filter each entry in our servers.lst file. We use regexes to check if a line matches a specific pattern, and we then use the <strong>Groups </strong>property to extract what was matched. If you don’t understand pattern matching, just skip the details. Learn it later, of course —it’s a fantastic way of dealing with text in almost any modern language.</li>
</ul>
<p>We will now add the final missing piece of the puzzle. Add the following to the namespace (<strong>not </strong>the Form1 class):</p>
<pre><span style="font-size:10pt;line-height:115%;font-family:&amp;">public</span><span style="font-size:10pt;line-height:115%;font-family:&amp;"> <span style="color:blue;">delegate </span><span style="color:blue;">void</span> <span style="color:#2b91af;">ShowConnectMsgDel</span>(<span style="color:#2b91af;">String</span> msg);</span></pre>
<p>Then, add the following function definition to the Form1 class:</p>
<pre><span style="font-size:10pt;font-family:&amp;">private </span><span style="font-size:10pt;font-family:&amp;"><span style="color:blue;">void</span> ShowConnectMsg(<span style="color:#2b91af;">String</span> msg)</span>
<span style="font-size:10pt;font-family:&amp;">{</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:#2b91af;">  Control</span> ctl = txtConsole;</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  if</span> (ctl.InvokeRequired)</span><span style="font-size:10pt;font-family:&amp;">
    ctl.Invoke(<span style="color:blue;">new</span> <span style="color:#2b91af;">ShowConnectMsgDel</span>(ShowConnectMsg), msg);</span>
<span style="font-size:10pt;font-family:&amp;"><span style="color:blue;">  else</span></span><span style="font-size:10pt;font-family:&amp;">
    ctl.Text = msg;</span>
<span style="font-size:10pt;line-height:115%;font-family:&amp;">}</span></pre>
<p>Our program will now compile. (I’ll explain delegates later, when it makes more sense to.) Run it, click the “Read” button, and you will see “Main game server” appear in the still-disabled Combo Box.</p>
<div id="attachment_219" class="wp-caption alignnone" style="width: 205px"><a href="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_loading_the_servers_file.png"><img title="post_9_pt1_loading_the_servers_file" src="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_loading_the_servers_file.png?w=195&#038;h=224" alt="A Properly-Formatted Servers File Is Parsed." width="195" height="224" /></a><p class="wp-caption-text">A Properly-Formatted Servers File Is Parsed.</p></div>
<p>If your program doesn’t compile, have a look at <a href="http://lthzelda.files.wordpress.com/2009/09/listing_1.pdf"><strong><span style="color:#0000ff;">Listing 1</span></strong></a> and try to figure out where you went wrong. (Apologies for the PDF; WordPress doesn&#8217;t like .txt files.) If it doesn’t load the server list, make sure you supplied the proper path to the EL Client folder.</p>
<p>Now, add the following code to the end of your <strong>ReadELFiles </strong>function:</p>
<pre><span style="font-size:10pt;font-family:&amp;">//Enable the remainder of our form</span>
<span style="font-size:10pt;font-family:&amp;">cmbServers.Enabled = <span style="color:blue;">true</span>;</span>
<span style="font-size:10pt;line-height:115%;font-family:&amp;">btnConnect.Enabled = <span style="color:blue;">true</span>;</span></pre>
<p>That should enable everything you need. Now, in Design mode, click on the “Connect” button and give it a click Event called <strong>ConnectToServer</strong>. You’ll be given a function skeleton again; here’s what we’ll add to it:</p>
<pre><span style="font-size:10pt;font-family:&amp;">private </span><span style="font-size:10pt;font-family:&amp;"><span style="color:blue;">void</span> ConnectToServer(<span style="color:blue;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</span>
<span style="font-size:10pt;font-family:&amp;">{</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:green;">  //Connect to our server</span></span>
  <span style="font-size:10pt;font-family:&amp;">UpdateConsole(<span style="color:#a31515;">"Connecting....."</span>);</span>
  <span style="font-size:10pt;font-family:&amp;">Thread t = <span style="color:blue;">new</span> Thread(<span style="color:blue;">new</span> ThreadStart(Check_Server));</span>  <span style="font-size:10pt;font-family:&amp;">
  t.IsBackground = <span style="color:blue;">true</span>;</span><span style="font-size:10pt;font-family:&amp;">
  t.Start();</span>
}</pre>
<p>This requires the <strong>CheckServers</strong> function, which will run in a separate thread:</p>
<pre><span style="font-size:10pt;font-family:&amp;">private</span><span style="font-size:10pt;font-family:&amp;"> <span style="color:blue;">void</span> Check_Server()</span>
<span style="font-size:10pt;font-family:&amp;">{</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:green;">  //Our middleware acts as a client in this case.</span></span>  <span style="font-size:10pt;font-family:&amp;">
  <span style="color:#2b91af;">TcpClient</span> tcpclnt = <span style="color:blue;">new</span> <span style="color:#2b91af;">TcpClient</span>();</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:#2b91af;">  Stream</span> srvStream;</span>
<span style="font-size:10pt;font-family:&amp;">
<span style="color:green;">  //Get our currently selected server and start it</span></span><span style="font-size:10pt;font-family:&amp;">
<span style="color:#2b91af;">  ServerInfo</span> sInfo = (<span style="color:#2b91af;">ServerInfo</span>)cmbServers.SelectedItem;</span>
  <span style="font-size:10pt;font-family:&amp;">tcpclnt.Connect(sInfo.address, sInfo.port);</span>
<span style="font-size:10pt;font-family:&amp;">
<span style="color:green;">  //Display any messages we receive.</span></span><span style="font-size:10pt;font-family:&amp;">
  srvStream = tcpclnt.GetStream();</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  byte</span>[] msg = <span style="color:blue;">new</span><span style="color:blue;"> byte</span>[1024];</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  bool</span> done = <span style="color:blue;">false</span>;</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  for</span> (; !done; )</span><span style="font-size:10pt;font-family:&amp;">
  {</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">    int</span> amtRead;</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">    try</span> {</span><span style="font-size:10pt;font-family:&amp;">
      amtRead = srvStream.Read(msg, 0, msg.Length);</span><span style="font-size:10pt;font-family:&amp;">
    } <span style="color:blue;">catch</span> (<span style="color:#2b91af;">IOException</span>) {</span><span style="font-size:10pt;font-family:&amp;">
      UpdateConsole(<span style="color:#a31515;">"\r\nIOException; closing Server"</span>);</span><span style="font-size:10pt;font-family:&amp;">
      amtRead = 0;</span><span style="font-size:10pt;font-family:&amp;">
    }</span>
<span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">    if</span> (amtRead != 0)</span><span style="font-size:10pt;font-family:&amp;">
    {</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:green;">      //Echo to console</span></span><span style="font-size:10pt;font-family:&amp;">
<span style="color:#2b91af;">      String</span> line = <span style="color:#a31515;">"MSG: ["</span>;</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">      for</span> (<span style="color:blue;">int</span> i=0; i&lt;amtRead; i++)</span><span style="font-size:10pt;font-family:&amp;">
      {</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">        byte</span> b = msg[i];</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">        if</span> (b &gt;= 32 &amp;&amp; b &lt;= 126)</span><span style="font-size:10pt;font-family:&amp;">
          line += (<span style="color:blue;">char</span>)b;</span><span style="font-size:10pt;font-family:&amp;">
        <span style="color:blue;">else</span></span><span style="font-size:10pt;font-family:&amp;">
          line += <span style="color:#a31515;">'.'</span>;</span><span style="font-size:10pt;font-family:&amp;">
      }</span><span style="font-size:10pt;font-family:&amp;">

      line += <span style="color:#a31515;">"]"</span>;</span><span style="font-size:10pt;font-family:&amp;">
      UpdateConsole(<span style="color:#a31515;">"\r\n"</span>+line);</span><span style="font-size:10pt;font-family:&amp;">
    }</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">    else</span></span><span style="font-size:10pt;font-family:&amp;">
    {</span><span style="font-size:10pt;font-family:&amp;">
      UpdateConsole(<span style="color:#a31515;">"\r\nRead zero; closing Server"</span>);</span><span style="font-size:10pt;font-family:&amp;">
      done = <span style="color:blue;">true</span>;</span><span style="font-size:10pt;font-family:&amp;">
    }</span><span style="font-size:10pt;font-family:&amp;">
  }</span>
<span style="font-size:10pt;font-family:&amp;">
<span style="color:green;">  //Must close BOTH</span></span><span style="font-size:10pt;font-family:&amp;">
  srvStream.Close();</span><span style="font-size:10pt;font-family:&amp;">
  tcpclnt.Close();</span>
<span style="font-size:10pt;font-family:&amp;">
<span style="color:green;">  //Ready to go again?</span></span><span style="font-size:10pt;font-family:&amp;">
  UpdateConsole(<span style="color:#a31515;">"\r\nServer Stopped"</span>);</span>
}</pre>
<p>Make sure you add the following <strong>using</strong> directives to the top of your file:</p>
<pre><span style="font-size:10pt;font-family:&amp;">using</span><span style="font-size:10pt;font-family:&amp;"> System.Threading;</span>
<span style="font-size:10pt;line-height:115%;font-family:&amp;">using</span><span style="font-size:10pt;line-height:115%;font-family:&amp;"> System.Net.Sockets;</span></pre>
<p>After that, you’ll only get errors for the <strong>UpdateConsole</strong> function, which we’ll implement now:</p>
<pre><span style="font-size:10pt;font-family:&amp;">private</span><span style="font-size:10pt;font-family:&amp;"><span style="color:blue;"> void</span> UpdateConsole(<span style="color:#2b91af;">String</span> msg)</span>
<span style="font-size:10pt;font-family:&amp;">{</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:#2b91af;">  Control</span> ctl = txtConsole;</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  if</span> (ctl.InvokeRequired)</span>  <span style="font-size:10pt;font-family:&amp;">
    ctl.Invoke(<span style="color:blue;">new</span> <span style="color:#2b91af;">AddToConsoleDel</span>(UpdateConsole), msg);</span><span style="font-size:10pt;font-family:&amp;">
<span style="color:blue;">  else</span></span><span style="font-size:10pt;font-family:&amp;">
    ctl.Text += msg;</span>
}</pre>
<p>Add the following to our namespace, and we’ll be done:</p>
<pre><span style="font-size:10pt;line-height:115%;font-family:&amp;">public</span><span style="font-size:10pt;line-height:115%;font-family:&amp;"> <span style="color:blue;">delegate</span><span style="color:blue;"> void</span> <span style="color:#2b91af;">AddToConsoleDel</span>(<span style="color:#2b91af;">String</span> msg);</span></pre>
<p>Run the program, click “Read” to get a server list, then choose the “Main game server” from your dropdown list and hit “Connect”. You should see a nascent echo of the regular log-in message, and some unreadable garbage.</p>
<div id="attachment_217" class="wp-caption alignnone" style="width: 227px"><a href="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_first_two_messages.png"><img class="size-medium wp-image-217" title="post_9_pt1_first_two_messages" src="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_first_two_messages.png?w=217&#038;h=250" alt="The &quot;Garbage&quot; Is Actually the Important Information, As We'll See Later." width="217" height="250" /></a><p class="wp-caption-text">The &quot;Garbage&quot; Is Actually the Important Information, As We&#39;ll See Later.</p></div>
<p>If this just doesn’t work, have a look at <a href="http://lthzelda.files.wordpress.com/2009/09/listing_2.pdf"><span style="color:#0000ff;"><strong>Listing 2</strong></span></a> to see where you went wrong.</p>
<p>If you scan the code, you’ll find everything in order. First, we create a <strong>TCPClient </strong>object to manage our TCP connection to the server. We then <strong>Connect </strong>it to the server, based on the item chosen in the drop-down list. Finally, we continue to read up to 1kb at a time from the server. To the best of my knowledge, the Eternal Lands server never sends more than a few hundred bytes of data at once, so we don’t have to merge messages.</p>
<p>Note that this all has to happen in a different thread, to avoid throttling the GUI dispatch thread. If you just ran a tight loop in the main Thread, your Windows Form would become sluggish and unresponsive. The C#-ism:</p>
<pre>  <span style="font-size:10pt;font-family:&amp;">Thread t = <span style="color:blue;">new</span> Thread(<span style="color:blue;">new</span> ThreadStart(Function_Name));</span></pre>
<p>…capitalizes on <strong>delegates </strong>to encapsulate a function (<strong>Function_Name</strong>) in a new thread. This is a reasonably good example of a delegate, but we have a much better one: our <strong>UpdateConsole </strong>function.</p>
<p>The problem with <strong>ThreadStart </strong>is that it’s too easy to guess what it does, without actually understanding why we choose to do it this way. Instead, let’s have a look at <strong>UpdateConsole</strong>. I’ve highlighted it differently below:</p>
<p>private void UpdateConsole(<span style="color:#ff0000;"><strong>String msg</strong></span>)<br />
{<br />
<span style="color:#ff0000;"><strong>Control ctl = txtConsole;</strong></span><br />
<span style="color:#0000ff;"><strong>if (ctl.InvokeRequired)</strong></span><br />
<span style="color:#800080;"><strong>ctl.Invoke(new AddToConsoleDel(UpdateConsole), msg);</strong></span><br />
<span style="color:#0000ff;"><strong>else</strong></span><br />
<span style="color:#008000;"><strong>ctl.Text += msg;</strong></span><br />
}</p>
<p>First, our variables are declared in red. One is the value we wish to update the console with (as a String) and the other is a local variable used to reference the Text Box itself. Since all Text Boxes subclass <strong>Control</strong>, we can store this variable in a generic fashion. Note that the variable <strong>ctl </strong>was created to emphasize that this technique can be used on any part of our form. We could have put <strong>ctl </strong>as a second function variable, if we had multiple consoles.</p>
<p>Next, the blue text. The “InvokeRequired” property (think of it like a read-only variable) is a nifty shorthand which tells us if the given control was created by the thread we are currently running. As all you GUI programmers know, most actions that update GUI components should be done in the master dispatch loop of the thread that created the GUI. If, for example, this control was created in a random thread which is now finished running, then updating it from another thread will cause all sorts of exceptions at run-time. We could dispatch a new thread for each update operation, but the <strong>InvokeRequired </strong>property helps us to avoid spawning threads when we don’t need to.</p>
<p>The purple text is run if an Invoke is Required. It calls the <strong>Invoke </strong>method of <strong>ctl</strong>, which adds a new event to a thread guaranteed to be valid for modifying <strong>ctl</strong>. This thread is of type <strong>AddToConsoleDel</strong>, which we defined earlier as:</p>
<p>delegate void AddToConsoleDel(String msg)</p>
<p>…in other words, as a delegated function with one argument that returns nothing (void). This matches the function signature of our <strong>UpdateConsole </strong>function. Look back at the purple text, and you’ll see that we call <strong>new AddToConsoleDel(UpdateConsole)</strong> to  create a new delegate of type <strong>AddToConsoleDel </strong>that will run the <strong>UpdateConsole </strong>function when called. The second parameter to <strong>Invoke </strong>is the argument set that we intend to pass to our <strong>AddToConsoleDel </strong>delegate. Since <strong>UpdateConsole </strong>only takes one argument, we only pass in one (<strong>msg</strong>).</p>
<p>Which leads us to the green text: what happens if we <em><strong>are </strong></em>running in the right thread. If this is the case, we simply append the message string to the Text Box’s existing <strong>Text </strong>property.</p>
<p>So, the logic of our function is simple. If the thread is capable of modifying the control directly, it just appends the text. Otherwise, it creates a new delegate to the same function, passes along the same method arguments, and asks the given control to <strong>Invoke </strong>this delegate. That ensures that next time the function is called (by the delegate this time) it has the necessary permission to modify the control. This logic is a bit tricky to catch the first time you see it, but it’s one of the main design patterns of C#. And, it has the benefit of keeping the actual logic of the method in the same place as the invoke logic of the delegate. So we can just call <strong>UpdateConsole </strong>and not have to care about whether a thread is spun off to do the dirty work.</p>
<p>You can think of a delegate as a pointer to a function, with enhanced type-safety, if that’s any easier for you.<br />
Take a break, grab a coffee, you deserve a break.</p>
<p><strong>Step 3: Passing Messages Along Properly</strong></p>
<p>Our middleware can locate the Eternal Lands server, and it establishes a TCP connection (proven by the fact that it receives two messages in sequence, not just two copies of the same message). We also jumped the gun and added a <strong>loopback </strong>entry to the client’s list of servers, to allow us to force the client to connect to our program instead of the real server. Now, let’s put that new entry to work, and tie the client and server together so that you can play <strong>Eternal Lands</strong> with our program as a local proxy.</p>
<p>Open your project in Visual Studio, and right-click on the “Solution” (top-most item) in the “Solution Explorer”. Choose “Add”, then “New Project”, then select “Class Library” and name it <strong>Eternal Lands Connector</strong>. Press “Ok”. Now, right-click on your main project (“Windows Forms Application 1”, in my case) and choose “Project Dependencies”. In the “Depends on” box, check the “Eternal Lands Connector” project. Click “Ok”.</p>
<p>The purpose of this secondary project is to isolate our code. Once we’ve written the C# necessary to tunnel messages from the client to the server, we’ll then be adding a whole bunch of filtering and display code. We don’t want to accidentally break our message passing code, so we’ll keep in a totally separate project. You could manage this project separately, and manually add the DLL to the main Windows Forms project each time you update it, but Visual Studio’s dependency tracker allows you to do this automatically.</p>
<p>Let’s get started. First, rename <strong>Class1.cs</strong> to <strong>ELMiddleware.cs</strong>. We’ll need another file, though (Right-click “Eternal Lands Connector”, choose “Add”, then “New Item…”, then select “Class”) called <strong>SleepQueue.cs</strong>. This queue manages a list of messages, and stops processing them when the queue is empty. It sets itself to sleep until a new message is received. This <strong>signaling</strong> approach is far more efficient than constantly checking if the queue has items (<strong>spinning</strong>). Here’s the code for this class:</p>
<pre><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Collections.Generic;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Linq;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Threading;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net.Sockets;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.IO;</span>

<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">namespace</span><span style="font-family:Courier New;font-size:10pt;"> Eternal_Lands_Connector</span>
{
<span style="font-family:Courier New;font-size:10pt;">  </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">abstract</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">class</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">SleepQueue</span> <span style="font-family:Courier New;font-size:10pt;">: </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IDisposable</span>
  {
<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //For threading: allow sleeping when no messages are received, by using an EventWaitHandle</span>
    <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span> <span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Thread</span> <span style="font-family:Courier New;font-size:10pt;">t;</span>
    <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span> <span style="color:#2b91af;font-family:Courier New;font-size:10pt;">EventWaitHandle</span> <span style="font-family:Courier New;font-size:10pt;">wHandle = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AutoResetEvent</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">);</span>
    <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Queue</span><span style="font-family:Courier New;font-size:10pt;">&lt;</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;">&gt; waitingMessages = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Queue</span><span style="font-family:Courier New;font-size:10pt;">&lt;</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;">&gt;();</span>

    <span style="color:#008000;font-family:Courier New;font-size:10pt;">//Add a packet to the list of waiting messages. </span>
    <span style="color:#008000;font-family:Courier New;font-size:10pt;">// Wake the main thread.</span>
    <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">virtual</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span> <span style="font-family:Courier New;font-size:10pt;">AddPacket(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span> <span style="font-family:Courier New;font-size:10pt;">p)</span>
    {
      <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">lock</span> <span style="font-family:Courier New;font-size:10pt;">(waitingMessages)</span>
        waitingMessages.Enqueue(p);
      wHandle.Set();
    }

    <span style="color:#008000;font-family:Courier New;font-size:10pt;">//What priority should the message queue thread be? </span>
    <span style="color:#008000;font-family:Courier New;font-size:10pt;">//  Sub-classes can override this to balance performance.</span>
    <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">virtual</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ThreadPriority</span><span style="font-family:Courier New;font-size:10pt;"> getInitialPriority()</span>
    {<span style="font-family:Courier New;font-size:10pt;">
      </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ThreadPriority</span><span style="font-family:Courier New;font-size:10pt;">.Normal;</span>
    }

<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //Dispose properly</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">    public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> Dispose()</span>
    {
      <span style="color:#008000;font-family:Courier New;font-size:10pt;">// Signal the consumer to exit.</span>
      <span style="font-family:Courier New;font-size:10pt;">AddPacket(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">     if</span><span style="font-family:Courier New;font-size:10pt;"> (t != </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">)</span>
        t.Join();
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">     if</span><span style="font-family:Courier New;font-size:10pt;"> (wHandle != </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">)</span>
        wHandle.Close();
    }

<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //Start the queueing process.</span><span style="font-family:Courier New;font-size:10pt;">
    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> startQueueing()</span>
    {
<span style="font-family:Courier New;font-size:10pt;">      t = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Thread</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ThreadStart</span><span style="font-family:Courier New;font-size:10pt;">(Handle_Queue));</span>
<span style="font-family:Courier New;font-size:10pt;">      t.IsBackground = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
      t.Priority = getInitialPriority();
      t.Start();
    }
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">
    private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> Handle_Queue()</span>
    {
<span style="font-family:Courier New;font-size:10pt;">      </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Do pre-inits</span>
      Pre_Init_Activity();
<span style="font-family:Courier New;font-size:10pt;">
</span><span style="color:#008000;font-family:Courier New;font-size:10pt;">      //Listen for queue updates</span>
<span style="font-family:Courier New;font-size:10pt;">      </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;"> msg = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">      for</span><span style="font-family:Courier New;font-size:10pt;"> (; </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.isValid(); )</span>
      {
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Get the next task</span><span style="font-family:Courier New;font-size:10pt;">
        msg = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">        lock</span><span style="font-family:Courier New;font-size:10pt;">(waitingMessages)</span>
         {
<span style="font-family:Courier New;font-size:10pt;">          </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (waitingMessages.Count &gt; 0)</span>
           {
             msg = waitingMessages.Dequeue();
<span style="font-family:Courier New;font-size:10pt;">           </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (msg == </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">)</span>
             {
<span style="font-family:Courier New;font-size:10pt;">             </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Done.</span><span style="font-family:Courier New;font-size:10pt;">
             </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.On_Message(msg);</span><span style="font-family:Courier New;font-size:10pt;">
             </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;">;</span>
             }
           }
         }

<span style="color:#008000;font-family:Courier New;font-size:10pt;">        //A bit confusing to have two null checks, but it makes sense.</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">        if</span><span style="font-family:Courier New;font-size:10pt;"> (msg == </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">)</span>
         {<span style="font-family:Courier New;font-size:10pt;">
          </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//No more tasks - wait for a signal</span>
              wHandle.WaitOne();
         }<span style="color:#0000ff;font-family:Courier New;font-size:10pt;"> else</span> {<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">
            this</span><span style="font-family:Courier New;font-size:10pt;">.On_Message(msg);</span>
         }
       }

<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">      this</span><span style="font-family:Courier New;font-size:10pt;">.On_Thread_Close();</span>
    }

<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //</span>
<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //Un-implemented functionality</span>
<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //</span>

<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //When does this queue exit?</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">    protected</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;"> abstract</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;"> bool</span><span style="font-family:Courier New;font-size:10pt;"> isValid();</span>

<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //What should we do with each message?</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">    protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">abstract</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> On_Message(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;"> msg);</span>

<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //What should happen when the thread closes?</span><span style="font-family:Courier New;font-size:10pt;"> </span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">    protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">abstract</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> On_Thread_Close();</span>

<span style="color:#008000;font-family:Courier New;font-size:10pt;">    //What should happen before the message loop begins? (After the thread is started)</span><span style="font-family:Courier New;font-size:10pt;">
    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">abstract</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> Pre_Init_Activity();</span>
  }
}</pre>
<p>This depends on the PacketData.cs file, which is simply a wrapper on a byte array coupled with an id character:</p>
<pre><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Collections.Generic;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Linq;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text;</span>

<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">namespace</span><span style="font-family:Courier New;font-size:10pt;"> Eternal_Lands_Connector</span>
{
  <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">class</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span>
  {
    <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> PacketData(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] data, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">char</span><span style="font-family:Courier New;font-size:10pt;"> from)</span>
    {
      <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.data = data;</span>
      <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.from = from;</span>
    }

    <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] data;</span>
    <span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">char</span><span style="font-family:Courier New;font-size:10pt;"> from;</span>
  }
}</pre>
<p>The technical details of the Sleep Queue are not important, so long as you realize that:</p>
<ol>
<li>Every message posted to the queue gets processed.</li>
<li>You can post <strong>null</strong> to stop processing and end the thread.</li>
<li>The thread takes up <strong>no</strong> CPU time when there are no messages waiting.</li>
<li>Sub-classes will have to tell the queue when to stop processing (naturally), what to do with messages that are received, and what to do directly before entering and after leaving the message loop.</li>
</ol>
<p>We now have everything we need to implement the <strong>ELMiddleware </strong>class, whose purpose is to handle all messages between the client and the server.</p>
<pre><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Collections.Generic;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Linq;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Threading;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net.Sockets;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.IO;</span>

<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">namespace</span><span style="font-family:Courier New;font-size:10pt;"> Eternal_Lands_Connector</span>
{
<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Global</span>
<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">delegate</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddPacketDel</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;"> msg);</span>
<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">delegate</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ShowConnectMsgDel</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> msg);</span>
<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">delegate</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> msg);</span>
<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">delegate</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IncrPacketCountDel</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> amt);</span>

<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">struct</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span>
    {
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> id;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> configDir;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> address;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> port;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> description;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> ToString()</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> description;</span>
        }
    }

<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">class</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELMiddleware</span><span style="font-family:Courier New;font-size:10pt;"> : </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">SleepQueue</span>
    {
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Hooks for controlling the client and server.</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> ELClientHook client;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> ELServerHook server;</span>

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Saved</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> currServer;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> loopback;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> elClientDir;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ShowConnectMsgDel</span><span style="font-family:Courier New;font-size:10pt;"> ShowConnect;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;"> UpdateConsole;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IncrPacketCountDel</span><span style="font-family:Courier New;font-size:10pt;"> IncrPacketCount;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> hookThreadID;</span>

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> AddPacket(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;"> p)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Log</span>
            IncrPacketCount(1);

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Count</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">base</span><span style="font-family:Courier New;font-size:10pt;">.AddPacket(p);</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> started = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> Started {</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> started;</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> ELMiddleware(ELClientHook client, ELServerHook server)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Save</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.client = client;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.server = server;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Hook</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.client.PacketHook = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddPacketDel</span><span style="font-family:Courier New;font-size:10pt;">(AddPacket);</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.server.PacketHook = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddPacketDel</span><span style="font-family:Courier New;font-size:10pt;">(AddPacket);</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> startAll(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> currServer, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> loopback, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> elClientDir, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ShowConnectMsgDel</span><span style="font-family:Courier New;font-size:10pt;"> ShowConnect, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;"> UpdateConsole, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IncrPacketCountDel</span><span style="font-family:Courier New;font-size:10pt;"> IncrPacketCount, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> hookThreadID)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Don't start twice</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (started || client.Started || server.Started)</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            started = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Save</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.currServer = currServer;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.loopback = loopback;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.elClientDir = elClientDir;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.ShowConnect = ShowConnect;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.UpdateConsole = UpdateConsole;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.IncrPacketCount = IncrPacketCount;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.hookThreadID = hookThreadID;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Start the sleep queues</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">base</span><span style="font-family:Courier New;font-size:10pt;">.startQueueing();</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> Pre_Init_Activity()</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Init Log</span>
<span style="font-family:Courier New;font-size:10pt;">            ShowConnect(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"EL Notifier Init"</span><span style="font-family:Courier New;font-size:10pt;">);</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Start the server</span>
            server.hookServer(currServer, UpdateConsole);

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Start the client</span>
            client.hookClient(loopback, elClientDir, UpdateConsole, hookThreadID);

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Spin-wait for both</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">while</span><span style="font-family:Courier New;font-size:10pt;"> (!server.ReadyForData || !client.ReadyForData)</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Thread</span><span style="font-family:Courier New;font-size:10pt;">.Sleep(5);</span>
<span style="font-family:Courier New;font-size:10pt;">            UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nSpin-waiting done"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
        }

<span style="font-family:Courier New;font-size:10pt;">       </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> On_Message(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;"> msg)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Count</span>
            IncrPacketCount(-1);
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (msg == </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">)</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Forward this message to the appropriate third party</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (msg.from == </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">'C'</span><span style="font-family:Courier New;font-size:10pt;">)</span>
            {
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Send from the client to the server.</span>
                server.sendData(msg.data);
            }
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (msg.from == </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">'S'</span><span style="font-family:Courier New;font-size:10pt;">)</span>
            {
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Send from the server to the client</span>
                client.sendData(msg.data);
            }
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span>
<span style="font-family:Courier New;font-size:10pt;">                UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nBad message code: "</span><span style="font-family:Courier New;font-size:10pt;"> + msg.from);</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> isValid()</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> client.Started &amp;&amp; server.Started;</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> On_Thread_Close()</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Make sure everything closed nicely</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (!server.Done)</span>
<span style="font-family:Courier New;font-size:10pt;">                server.Done = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (!client.Done)</span>
<span style="font-family:Courier New;font-size:10pt;">                client.Done = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Done</span>
<span style="font-family:Courier New;font-size:10pt;">            started = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
        }
    }
}</pre>
<p>Add two more classes to the project, called <strong>ELClientHook.cs</strong> and <strong>ELServerHook.cs</strong>, respectively. Mark each class <strong>public</strong>, but don’t add any implementation yet.</p>
<p>Let’s review the code for <strong>ELMiddleware</strong>. At the top, we have some global delegate definitions, presumably used for logging. We also have our <strong>ServerInfo </strong>struct —if you think this means we’ll be removing a lot of code from <strong>Form1.cs</strong> then you guessed right. Our <strong>ELMiddleware </strong>class extends the <strong>SleepQueue </strong>abstract class. It contains several delegate references, a mysterious <strong>hookThreadID</strong>, and a reference to our client and server hooks.</p>
<p>Most of the code after this is obvious, and should give you an idea what kind of functionality we’ll need in <strong>ELClientHook</strong> and <strong>ELServerHook</strong>. The <strong>onMessage()</strong> function simply checks the sender of the message, and then ferries the message across to the recipient. We will later add the ability to react to ‘<strong>S</strong>’ class messages.</p>
<p>Our client and server hooks will need to be able to “take” messages from the middleware, in addition to other miscellaneous features. First, let’s add <strong>ELServerHook</strong>. Its functionality will be very similar to the previous chapter’s exercises.</p>
<pre><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Collections.Generic;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Linq;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.IO;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net.Sockets;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Threading;</span>

<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">namespace</span><span style="font-family:Courier New;font-size:10pt;"> Eternal_Lands_Connector</span>
{
<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">class</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELServerHook</span>
    {
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">TcpClient</span><span style="font-family:Courier New;font-size:10pt;"> tcpclnt;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Stream</span><span style="font-family:Courier New;font-size:10pt;"> srvStream;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> srv;</span>

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Callbacks</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;"> UpdateConsole;</span>
<span style="font-family:Courier New;font-size:10pt;">
        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> started = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> Started {</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> started;</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> done;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> Done {</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> done;</span>
            }
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">set</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                done = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">value</span><span style="font-family:Courier New;font-size:10pt;">;</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> readyForData = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> ReadyForData {</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> readyForData;</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddPacketDel</span><span style="font-family:Courier New;font-size:10pt;"> packetDel;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddPacketDel</span><span style="font-family:Courier New;font-size:10pt;"> PacketHook {</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">               </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.packetDel;</span>
            }
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">set</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.packetDel = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">value</span><span style="font-family:Courier New;font-size:10pt;">;</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> hookServer(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> srv, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;"> UpdateConsole)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Don't start twice</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (started)</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            started = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Save</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.srv = srv;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.UpdateConsole = UpdateConsole;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Start</span>
<span style="font-family:Courier New;font-size:10pt;">            tcpclnt = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">TcpClient</span><span style="font-family:Courier New;font-size:10pt;">();</span>
<span style="font-family:Courier New;font-size:10pt;">            UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Connecting....."</span><span style="font-family:Courier New;font-size:10pt;">);</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Thread</span><span style="font-family:Courier New;font-size:10pt;"> t = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Thread</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ThreadStart</span><span style="font-family:Courier New;font-size:10pt;">(Check_Server));</span>
<span style="font-family:Courier New;font-size:10pt;">            t.IsBackground = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
            t.Start();
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> sendData(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] data)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (!readyForData)</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">throw</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Exception</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Server is not ready for messsages"</span><span style="font-family:Courier New;font-size:10pt;">);</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Send the dat down this stream. Technically, this occurs in the middleware's thread,</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//   so it won't conflict with any data we're reading at the same time.</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">try</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
                srvStream.Write(data, 0, data.Length);
<span style="font-family:Courier New;font-size:10pt;">            } </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">catch</span><span style="font-family:Courier New;font-size:10pt;"> (</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Exception</span><span style="font-family:Courier New;font-size:10pt;"> ex) {</span>
<span style="font-family:Courier New;font-size:10pt;">                UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nException writing to server: \r\n   "</span><span style="font-family:Courier New;font-size:10pt;"> + ex.ToString());</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> Check_Server()</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Connect to the server's TCP port.</span>
            tcpclnt.Connect(srv.address, srv.port);
<span style="font-family:Courier New;font-size:10pt;">            readyForData = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Connected"</span><span style="font-family:Courier New;font-size:10pt;">);</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Try reading a bit</span>
            srvStream = tcpclnt.GetStream();
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] msg = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[1024];</span>
<span style="font-family:Courier New;font-size:10pt;">            done = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">for</span><span style="font-family:Courier New;font-size:10pt;"> (; !done; )</span>
            {
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> amtRead;</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">try</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
                    amtRead = srvStream.Read(msg, 0, msg.Length);
<span style="font-family:Courier New;font-size:10pt;">                } </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">catch</span><span style="font-family:Courier New;font-size:10pt;"> (</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IOException</span><span style="font-family:Courier New;font-size:10pt;">) {</span>
<span style="font-family:Courier New;font-size:10pt;">                    UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nIOException; closing Server"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
                    amtRead = 0;
                }

<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (amtRead != 0)</span>
                {
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Make a new packet, add it to the middleware's queue</span>
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] pk = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[amtRead];</span>
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Array</span><span style="font-family:Courier New;font-size:10pt;">.Copy(msg, pk, amtRead);</span>
<span style="font-family:Courier New;font-size:10pt;">                    PacketHook(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;">(pk, </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">'S'</span><span style="font-family:Courier New;font-size:10pt;">));</span>
                }
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span>
                {
<span style="font-family:Courier New;font-size:10pt;">                    UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nRead zero; closing Server"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">                    done = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
                }
            }

<span style="font-family:Courier New;font-size:10pt;">           </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Must close BOTH</span>
            srvStream.Close();
            tcpclnt.Close();

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Ready to go again?</span>
<span style="font-family:Courier New;font-size:10pt;">            UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nServer Stopped"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Console</span><span style="font-family:Courier New;font-size:10pt;">.WriteLine(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Server hook stopped"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">            started = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
        }
    }
}</pre>
<p>The implementation is almost exactly what we had before. The call to <strong>srvStream</strong>.<strong>Read()</strong> is blocking, by the way —no Sleep Queue is necessary.</p>
<p>The <strong>ELClientHook </strong>implementation is much more elusive:</p>
<pre><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Collections.Generic;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Linq;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.IO;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net.Sockets;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text.RegularExpressions;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Diagnostics;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Threading;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Windows.Forms;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Runtime.InteropServices;</span>

<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">namespace</span><span style="font-family:Courier New;font-size:10pt;"> Eternal_Lands_Connector</span>
{
<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Just a helper class; no threads.</span>
<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">class</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELClientHook</span>
    {
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Const</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">const</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">string</span><span style="font-family:Courier New;font-size:10pt;"> SERVER_ADDR = </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"127.0.0.1"</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">const</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> SERVER_PORT = 5421;</span>

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> loopback;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> elClientDir;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">TcpListener</span><span style="font-family:Courier New;font-size:10pt;"> listener;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Stream</span><span style="font-family:Courier New;font-size:10pt;"> clientStr;</span>

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Form</span><span style="font-family:Courier New;font-size:10pt;"> mainForm;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> hookThreadID;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> elDone = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> started = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> Started {</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> started;</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> done;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> Done {</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> done;</span>
            }
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">set</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                done = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">value</span><span style="font-family:Courier New;font-size:10pt;">;</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> readyForData = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> ReadyForData {</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> readyForData;</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddPacketDel</span><span style="font-family:Courier New;font-size:10pt;"> packetDel;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddPacketDel</span><span style="font-family:Courier New;font-size:10pt;"> PacketHook {</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.packetDel;</span>
            }
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">set</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.packetDel = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">value</span><span style="font-family:Courier New;font-size:10pt;">;</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Callbacks</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;"> UpdateConsole;</span>
<span style="font-family:Courier New;font-size:10pt;">
        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> hookClient(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> loopback, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> elClientDir, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;"> UpdateConsole, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> hookThreadID)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Don't start twice</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (started)</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            started = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Save</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.loopback = loopback;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.UpdateConsole = UpdateConsole;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.elClientDir = elClientDir;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.hookThreadID = hookThreadID;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Start background client</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Thread</span><span style="font-family:Courier New;font-size:10pt;"> t = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Thread</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ThreadStart</span><span style="font-family:Courier New;font-size:10pt;">(Start_Client));</span>
<span style="font-family:Courier New;font-size:10pt;">            t.IsBackground = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
             t.Start();
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> sendData(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] data)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (!readyForData)</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">throw</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Exception</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Server is not ready for messsages"</span><span style="font-family:Courier New;font-size:10pt;">);</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Send the dat down this stream. Technically, this occurs in the middleware's thread,</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//   so it won't conflict with any data we're reading at the time.</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">try</span><span style="font-family:Courier New;font-size:10pt;"> {</span>
                clientStr.Write(data, 0, data.Length);

<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Logging code - uncomment for development</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">/*StringBuilder sb = new StringBuilder();</span>
<span style="color:#008000;">                sb.Append("\r\nClient Write: [");
                foreach (byte b in data)
                    sb.Append(Convert.ToString(b, 16).PadLeft(2, '0') + ":");
                sb.Append("]");
               UpdateConsole(sb.ToString());*/</span>
<span style="font-family:Courier New;font-size:10pt;">            } </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">catch</span><span style="font-family:Courier New;font-size:10pt;"> (</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Exception</span><span style="font-family:Courier New;font-size:10pt;"> ex) {</span>
<span style="font-family:Courier New;font-size:10pt;">                UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nException writing to client: \r\n   "</span><span style="font-family:Courier New;font-size:10pt;"> + ex.ToString());</span>
            }
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> EL_Stopped(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Object</span><span style="font-family:Courier New;font-size:10pt;"> sender, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">EventArgs</span><span style="font-family:Courier New;font-size:10pt;"> e)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            elDone = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Get our handle (no idea why this requires an invoke... maybe it creates it?)</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">delegate</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IntPtr</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">GetFormHandleDel</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Form</span><span style="font-family:Courier New;font-size:10pt;"> f);</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IntPtr</span><span style="font-family:Courier New;font-size:10pt;"> GetFormHandle(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Form</span><span style="font-family:Courier New;font-size:10pt;"> f)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (f.InvokeRequired)</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> (</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IntPtr</span><span style="font-family:Courier New;font-size:10pt;">)f.Invoke(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">GetFormHandleDel</span><span style="font-family:Courier New;font-size:10pt;">(GetFormHandle), f);</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> f.Handle;</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> findMainForm(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;">[] allowedProcessIDs, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> matcherRegex, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> hookThreadID)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> EL_Window_Activate()</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Console</span><span style="font-family:Courier New;font-size:10pt;">.WriteLine(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"EL Client Window Activated"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> EL_Window_Deactivate()</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Console</span><span style="font-family:Courier New;font-size:10pt;">.WriteLine(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"EL Client Window Deactivated"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> Start_Client()</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Start the socket</span>
<span style="font-family:Courier New;font-size:10pt;">            listener = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">TcpListener</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IPAddress</span><span style="font-family:Courier New;font-size:10pt;">.Parse(SERVER_ADDR), SERVER_PORT);</span>
            listener.Start();
<span style="font-family:Courier New;font-size:10pt;">           UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nLoopback server running at: "</span><span style="font-family:Courier New;font-size:10pt;"> + listener.LocalEndpoint);</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Start the EL client program with the server specified as "loopback"</span>
<span style="font-family:Courier New;font-size:10pt;">            UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nStarting EL Client..."</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ProcessStartInfo</span><span style="font-family:Courier New;font-size:10pt;"> ps = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ProcessStartInfo</span><span style="font-family:Courier New;font-size:10pt;">();</span>
<span style="font-family:Courier New;font-size:10pt;">            ps.FileName = elClientDir + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\\el.exe"</span><span style="font-family:Courier New;font-size:10pt;">;</span>
            ps.Arguments = loopback.id;
            ps.WorkingDirectory = elClientDir;
<span style="font-family:Courier New;font-size:10pt;">            ps.ErrorDialog = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Process</span><span style="font-family:Courier New;font-size:10pt;"> p = </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Process</span><span style="font-family:Courier New;font-size:10pt;">.Start(ps);</span>
<span style="font-family:Courier New;font-size:10pt;">            elDone = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            p.Exited += </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">EventHandler</span><span style="font-family:Courier New;font-size:10pt;">(EL_Stopped);</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Get the full-screen window for this application</span>
<span style="font-family:Courier New;font-size:10pt;">            mainForm = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">while</span><span style="font-family:Courier New;font-size:10pt;"> (mainForm == </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">)</span>
            {
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;">[] validIDs = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;">[p.Threads.Count];</span>
                {
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> id = 0;</span>
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">foreach</span><span style="font-family:Courier New;font-size:10pt;"> (</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ProcessThread</span><span style="font-family:Courier New;font-size:10pt;"> t </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">in</span><span style="font-family:Courier New;font-size:10pt;"> p.Threads)</span>
                        validIDs[id++] = t.Id;
                }

<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (findMainForm(validIDs, </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Eternal Lands"</span><span style="font-family:Courier New;font-size:10pt;">, hookThreadID))</span>
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">break</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Thread</span><span style="font-family:Courier New;font-size:10pt;">.Sleep(5);</span>
            }
<span style="font-family:Courier New;font-size:10pt;">            UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nClient spin-waiting done"</span><span style="font-family:Courier New;font-size:10pt;">);</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Wait for the client to try to connect to us</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">TcpClient</span><span style="font-family:Courier New;font-size:10pt;"> socket = listener.AcceptTcpClient();</span>
            clientStr = socket.GetStream();
<span style="font-family:Courier New;font-size:10pt;">            readyForData = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nEL Client tried to connect to us: "</span><span style="font-family:Courier New;font-size:10pt;"> + socket.Client.RemoteEndPoint);</span>

 <span style="font-family:Courier New;font-size:10pt;">           </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Continually read from the client. This is the main client update thread.</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] msg = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[1024];</span>
<span style="font-family:Courier New;font-size:10pt;">            done = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">for</span><span style="font-family:Courier New;font-size:10pt;"> (; !done; )</span>
            {
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Is the client still running?</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (elDone)</span>
                {
<span style="font-family:Courier New;font-size:10pt;">                    UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nGame closed; closing Client"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">                    done = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
                }
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span>
                {
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> amtRead;</span>
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">try</span>
                    {
                       amtRead = clientStr.Read(msg, 0, msg.Length);
                    }
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">catch</span><span style="font-family:Courier New;font-size:10pt;"> (</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IOException</span><span style="font-family:Courier New;font-size:10pt;">)</span>
                    {
<span style="font-family:Courier New;font-size:10pt;">                        UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nIOException; closing Client"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
                        amtRead = 0;
                    }
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (amtRead != 0)</span>
                    {
<span style="font-family:Courier New;font-size:10pt;">                       </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Make a new packet, add it to the middleware's queue</span>
<span style="font-family:Courier New;font-size:10pt;">                        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] pk = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[amtRead];</span>
<span style="font-family:Courier New;font-size:10pt;">                        </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Array</span><span style="font-family:Courier New;font-size:10pt;">.Copy(msg, pk, amtRead);</span>
<span style="font-family:Courier New;font-size:10pt;">                        PacketHook(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;">(pk, </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">'C'</span><span style="font-family:Courier New;font-size:10pt;">));</span>
                    }
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span>
                    {
<span style="font-family:Courier New;font-size:10pt;">                        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//We're done</span>
<span style="font-family:Courier New;font-size:10pt;">                        UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nRead zero; closing Client"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">                        done = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
                    }
                }
            }

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Have to close all three</span>
            clientStr.Close();
            socket.Close();
            listener.Stop();

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Ready to go again?</span>
<span style="font-family:Courier New;font-size:10pt;">            UpdateConsole(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\r\nClient Stopped"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Console</span><span style="font-family:Courier New;font-size:10pt;">.WriteLine(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Client hook stopped"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">            started = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
        }
    }
}</pre>
<p>You might get an error with the <strong>System.Windows.Forms</strong> using directive; simply right-click on the “References” section of your Connector’s Project file and choose “Add Reference”. Then, in the “.NET” tab, browse down to “System.Windows.Forms” and click “Ok”. By default, a library project does not have access to the <strong>Forms </strong>dll, for reasons that remain a mystery to me.</p>
<p>A quick browse through this code reveals that our fake middleware server will be situated at <strong>127.0.0.1</strong>, on port <strong>5421</strong>. The <strong>sendData</strong>() function is similar to the server’s copy; however, I’ve included some logging code for your convenience. If you uncomment this, it will print a properly-formatted hexadecimal representation of each message sent from the server to the client. This will allow you to manually debug unknown or tricky messages, and to determine how you should react to them.</p>
<p>The <strong>findMainForm</strong>() function is currently empty; it will later be used to determine which window is actually hosting the <strong>EL </strong>client. The only other function of interest is the <strong>StartClient</strong>() function. Note that we use a <strong>ProcessStartInfo</strong> object to handle starting a process:</p>
<p>1.We have to set the working directory to the Eternal Lands folder, otherwise the process won’t be able to find its resources (images, sounds, etc.).<br />
2.We start the process<strong> el.exe</strong>. This, of course, is Windows-specific.<br />
3.We start this process with the argument <strong>loopback</strong>. In other words, we call “<strong>el.exe loopback</strong>” from the command line, allowing us to choose which server to connect to.</p>
<p>The Thread-finding code which follows this is messy; just ignore it. Basically, our middleware program will have multiple running threads, and we need to figure out which one is hosting the <strong>EL Client’s</strong> window. That way, we can detect when it has focus, and avoid showing messages in that case.</p>
<p>Note that, like the server, the client continually reads from the middleware until no more data is sent. You’ll have to change <strong>Form1</strong>’s code to actually <em><strong>use </strong></em>this new middleware, of course.</p>
<pre><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Collections.Generic;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.ComponentModel;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Data;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Drawing;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Linq;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Windows.Forms;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> Eternal_Lands_Connector;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text.RegularExpressions;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.IO;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Threading;</span>
<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net.Sockets;</span>

<span style="color:#0000ff;font-family:Courier New;font-size:10pt;">namespace</span><span style="font-family:Courier New;font-size:10pt;"> WindowsFormsApplication1</span>
{
<span style="font-family:Courier New;font-size:10pt;">    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">partial</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">class</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Form1</span><span style="font-family:Courier New;font-size:10pt;"> : </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Form</span>
    {
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Count leftover packets. A good first-warning if something goes wrong.</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> packetCount;</span>

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Our hooks</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELServerHook</span><span style="font-family:Courier New;font-size:10pt;"> serverHook;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELClientHook</span><span style="font-family:Courier New;font-size:10pt;"> clientHook;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELMiddleware</span><span style="font-family:Courier New;font-size:10pt;"> middleWare;</span>

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Also...</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> loopbackInfo;</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">string</span><span style="font-family:Courier New;font-size:10pt;"> srvLine = </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"loopback        main            "</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELClientHook</span><span style="font-family:Courier New;font-size:10pt;">.SERVER_ADDR + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"               "</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELClientHook</span><span style="font-family:Courier New;font-size:10pt;">.SERVER_PORT + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"    Loopback adapter for use with the EL Notifier"</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> Form1()</span>
        {
            InitializeComponent();

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Initialize connectors.</span>
<span style="font-family:Courier New;font-size:10pt;">            serverHook = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELServerHook</span><span style="font-family:Courier New;font-size:10pt;">();</span>
<span style="font-family:Courier New;font-size:10pt;">            clientHook = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELClientHook</span><span style="font-family:Courier New;font-size:10pt;">();</span>
<span style="font-family:Courier New;font-size:10pt;">            middleWare = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELMiddleware</span><span style="font-family:Courier New;font-size:10pt;">(clientHook, serverHook);</span>
        }

 <span style="font-family:Courier New;font-size:10pt;">       </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> ReadELFiles(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">object</span><span style="font-family:Courier New;font-size:10pt;"> sender, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">EventArgs</span><span style="font-family:Courier New;font-size:10pt;"> e)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Reload an entirely new list of servers.</span>
            cmbServers.Items.Clear();

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Don’t load anything if we specified an invalid directory.</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (!</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">File</span><span style="font-family:Courier New;font-size:10pt;">.Exists(txtPathToELFolder.Text + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\\"</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"el.exe"</span><span style="font-family:Courier New;font-size:10pt;">))</span>
            {
<span style="font-family:Courier New;font-size:10pt;">                txtConsole.Text = </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Error: el.exe doesn't exist in EL folder"</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;">;</span>
            }
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (!</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">File</span><span style="font-family:Courier New;font-size:10pt;">.Exists(txtPathToELFolder.Text + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\\"</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"servers.lst"</span><span style="font-family:Courier New;font-size:10pt;">))</span>
            {
<span style="font-family:Courier New;font-size:10pt;">                txtConsole.Text = </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Error: servers.lst doesn't exist in EL folder"</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;">;</span>
            }

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Open our servers file and read it.</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> foundLoopback = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">StreamReader</span><span style="font-family:Courier New;font-size:10pt;"> srvFile = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">StreamReader</span><span style="font-family:Courier New;font-size:10pt;">(txtPathToELFolder.Text + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\\"</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"servers.lst"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">while</span><span style="font-family:Courier New;font-size:10pt;"> (!srvFile.EndOfStream)</span>
            {
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> line = srvFile.ReadLine();</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (line == </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">)</span>
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">break</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Coment? Empty?</span>
                line = line.Trim();
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (line.StartsWith(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"#"</span><span style="font-family:Courier New;font-size:10pt;">) || line.Length == 0)</span>
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">continue</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Read:</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//ID, Config_Dir, Address, Port, Description</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> regex = </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"([^ \t]+)[ \t]+([^ \t]*)[ \t]+([^ \t]*)[ \t]+([^ \t]*)[ \t]+(.*)"</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Match</span><span style="font-family:Courier New;font-size:10pt;"> m = </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Regex</span><span style="font-family:Courier New;font-size:10pt;">.Match(line, regex);</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> sInf = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;">();</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (m.Success &amp;&amp; m.Groups.Count == 6)</span>
                {
                    sInf.id = m.Groups[1].Value;
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (sInf.id.Equals(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"loopback"</span><span style="font-family:Courier New;font-size:10pt;">))</span>
<span style="font-family:Courier New;font-size:10pt;">                        foundLoopback = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
                    sInf.configDir = m.Groups[2].Value;
                    sInf.address = m.Groups[3].Value;
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">try</span>
                    {
<span style="font-family:Courier New;font-size:10pt;">                        sInf.port = </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Int32</span><span style="font-family:Courier New;font-size:10pt;">.Parse(m.Groups[4].Value);</span>
                    }
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">catch</span><span style="font-family:Courier New;font-size:10pt;"> (</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">FormatException</span><span style="font-family:Courier New;font-size:10pt;">)</span>
                    {
<span style="font-family:Courier New;font-size:10pt;">                        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Don't add</span>
<span style="font-family:Courier New;font-size:10pt;">                        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">continue</span><span style="font-family:Courier New;font-size:10pt;">;</span>
                    }
                    sInf.description = m.Groups[5].Value;
                    cmbServers.Items.Add(sInf);

<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Loopback?</span>
<span style="font-family:Courier New;font-size:10pt;">                    </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (sInf.id.Equals(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"loopback"</span><span style="font-family:Courier New;font-size:10pt;">))</span>
                        loopbackInfo = sInf;
                }
            }
            srvFile.Close();

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Do we need to add our own local server?</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (!foundLoopback)</span>
            {
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Copy existing server file</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">StreamReader</span><span style="font-family:Courier New;font-size:10pt;"> inFile = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">StreamReader</span><span style="font-family:Courier New;font-size:10pt;">(txtPathToELFolder.Text + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\\"</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"servers.lst"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">StreamWriter</span><span style="font-family:Courier New;font-size:10pt;"> outFile = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">StreamWriter</span><span style="font-family:Courier New;font-size:10pt;">(txtPathToELFolder.Text + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\\"</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"servers.lst.new"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">for</span><span style="font-family:Courier New;font-size:10pt;"> (</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> line = inFile.ReadLine(); line != </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">; line = inFile.ReadLine())</span>
                    outFile.WriteLine(line);
                inFile.Close();

<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Add our own category</span>
                outFile.WriteLine(srvLine);

<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Close, swap, notify.</span>
                outFile.Close();
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">File</span><span style="font-family:Courier New;font-size:10pt;">.Delete(txtPathToELFolder.Text + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\\"</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"servers.lst"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">File</span><span style="font-family:Courier New;font-size:10pt;">.Move(txtPathToELFolder.Text + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\\"</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"servers.lst.new"</span><span style="font-family:Courier New;font-size:10pt;">, txtPathToELFolder.Text + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"\\"</span><span style="font-family:Courier New;font-size:10pt;"> + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"servers.lst"</span><span style="font-family:Courier New;font-size:10pt;">);</span>
<span style="font-family:Courier New;font-size:10pt;">                ShowConnectMsg(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"Created loopback entry."</span><span style="font-family:Courier New;font-size:10pt;">);</span>

<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Add a new item to the list</span>
<span style="font-family:Courier New;font-size:10pt;">                loopbackInfo = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;">();</span>
<span style="font-family:Courier New;font-size:10pt;">                loopbackInfo.id = </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"loopback"</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">                loopbackInfo.configDir = </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"main"</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">                loopbackInfo.address = </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELClientHook</span><span style="font-family:Courier New;font-size:10pt;">.SERVER_ADDR;</span>
<span style="font-family:Courier New;font-size:10pt;">                loopbackInfo.port = </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ELClientHook</span><span style="font-family:Courier New;font-size:10pt;">.SERVER_PORT;</span>
                cmbServers.Items.Add(loopbackInfo);
            }

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (cmbServers.Items.Count &gt; 0)</span>
                cmbServers.SelectedIndex = 0;

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Enable the remainder of our form</span>
<span style="font-family:Courier New;font-size:10pt;">            cmbServers.Enabled = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
<span style="font-family:Courier New;font-size:10pt;">            btnConnect.Enabled = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> ConnectToServer(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">object</span><span style="font-family:Courier New;font-size:10pt;"> sender, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">EventArgs</span><span style="font-family:Courier New;font-size:10pt;"> e)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (middleWare.Started || clientHook.Started || serverHook.Started)</span>
<span style="font-family:Courier New;font-size:10pt;">                </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;">;</span>

<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Count</span>
            packetCount = 0;
<span style="font-family:Courier New;font-size:10pt;">
            </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Get our currently-selected server and start it.</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;"> srv = (</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;">)cmbServers.SelectedItem;</span>
<span style="font-family:Courier New;font-size:10pt;">            middleWare.startAll(srv, loopbackInfo, txtPathToELFolder.Text, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ShowConnectMsgDel</span><span style="font-family:Courier New;font-size:10pt;">(ShowConnectMsg), </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;">(UpdateConsole), </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">IncrPacketCountDel</span><span style="font-family:Courier New;font-size:10pt;">(IncrPacketCount), </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Thread</span><span style="font-family:Courier New;font-size:10pt;">.CurrentThread.ManagedThreadId);</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Delegates and implementation details</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> ShowConnectMsg(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> msg)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Control</span><span style="font-family:Courier New;font-size:10pt;"> ctl = txtConsole;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (ctl.InvokeRequired)</span>
<span style="font-family:Courier New;font-size:10pt;">                ctl.Invoke(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ShowConnectMsgDel</span><span style="font-family:Courier New;font-size:10pt;">(ShowConnectMsg), msg);</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span>
                ctl.Text = msg;
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> UpdateConsole(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> msg)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Control</span><span style="font-family:Courier New;font-size:10pt;"> ctl = txtConsole;</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (ctl.InvokeRequired)</span>
<span style="font-family:Courier New;font-size:10pt;">                ctl.Invoke(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;">(UpdateConsole), msg);</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span>
                ctl.Text += msg;
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> IncrPacketCount(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> amt)</span>
        {
            packetCount += amt;
<span style="font-family:Courier New;font-size:10pt;">            SetText(lblZero, packetCount + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">""</span><span style="font-family:Courier New;font-size:10pt;">);</span>
        }

<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">delegate</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">SetTextDel</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Control</span><span style="font-family:Courier New;font-size:10pt;"> ctl, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> msg);</span>
<span style="font-family:Courier New;font-size:10pt;">        </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> SetText(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Control</span><span style="font-family:Courier New;font-size:10pt;"> ctl, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;"> msg)</span>
        {
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (ctl.InvokeRequired)</span>
<span style="font-family:Courier New;font-size:10pt;">                ctl.Invoke(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">SetTextDel</span><span style="font-family:Courier New;font-size:10pt;">(SetText), ctl, msg);</span>
<span style="font-family:Courier New;font-size:10pt;">            </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">else</span>
                ctl.Text = msg;
        }
    }
}</pre>
<p>Right-click on the References section in your main Forms project and choose “Add Reference”. Then, in the “Projects” tab, choose “Eternal Lands Connector” and hit “Ok”. This will allow you to use our class library.</p>
<p>The source code is not too complex, and the effect is easy enough to describe: we simply intercept and then deliver all messages from the client to the server, and from the server to the client. At the moment, this is essentially a whole lot of work for nothing. However, now that all messages are passing through our program (our source code, you might say), you can easily  tag messages of a specific type, and prompt the user after further processing them. So, this was all “legwork”.</p>
<div id="attachment_234" class="wp-caption alignnone" style="width: 197px"><a href="http://lthzelda.files.wordpress.com/2009/10/post_9_pt1_cross_the_streams.png"><img class="size-medium wp-image-234" title="post_9_pt1_cross_the_streams" src="http://lthzelda.files.wordpress.com/2009/10/post_9_pt1_cross_the_streams.png?w=187&#038;h=116" alt="Our middleware in action, connecting to the PK server." width="187" height="116" /></a><p class="wp-caption-text">Our middleware in action, connecting to the PK server.</p></div>
<p>Congratulations, we have now bamboozled both end points. In the next section, we’ll consider how to filter messages without requiring a re-compile of the Connector each time we change our minds about which messages to filter. We&#8217;ll also get you started processing Eternal Lands&#8217;s images to brighten up our notifier.</p>
<p><strong>Step 4: Filtering Messages (Outside the Core)</strong></p>
<p>At this point, you should have a pretty good idea how to intercept messages of a certain type. Before you dash too far into it, though, may I remind you that one of the reasons we used C# in the first place was to avoid bugs that corrupted our communication layer. We should add the following to the communication core:</p>
<ol>
<li>Allow our main Forms class to “register” any number of listeners with the core.</li>
<li>Before sending a message (to the client), check if it matches any of the listeners&#8217; patterns. If it does, send a copy of the message to the matched listener.</li>
<li>Ensure that the core runs in a higher-priority thread than the listeners&#8217; implementations. According to the rules of Windows thread priorities, this ensures that the listeners cannot starve the core for cycles.</li>
</ol>
<p>This way, no amount of chicanery by the listeners can cause the core to malfunction. (And remember, malfunctions are BAD, since we&#8217;re not the ones paying for the EL servers.)</p>
<p>Open up <strong>ELMiddleware.cs</strong>, and add the following member variable to the class:</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;font-weight:normal;">//An additional matcher</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> MessageMatcher msgMatch;</span></p>
<p>We&#8217;ll define <strong>MessageMatcher </strong>later; for now, scroll down to the definition of <strong>startAll</strong>, and change it to read:</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;font-weight:normal;">public</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;font-weight:normal;">void</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> startAll(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;font-weight:normal;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> currServer, MessageMatcher msgMatch, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;font-weight:normal;">ServerInfo</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> loopback, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;font-weight:normal;">String</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> elClientDir, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;font-weight:normal;">ShowConnectMsgDel</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> ShowConnect, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;font-weight:normal;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> UpdateConsole, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;font-weight:normal;">IncrPacketCountDel</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> IncrPacketCount, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;font-weight:normal;">int</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> hookThreadID)</span></p>
<p>Next, somewhere in the body of startAll, save the MessageMatcher that we passed in to the function:</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;font-weight:normal;">this</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;">.msgMatch = msgMatch;</span></p>
<p>Make sure you start it too; after “base.startQueueing()” add:</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-weight:normal;">msgMatch.startQueueing();</p>
<p>And finally, scroll down until you find the line:</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-weight:normal;">client.sendData(msg.data);</p>
<p>&#8230;and add the following underneath it:</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#008000;font-weight:normal;">//Send the data to an additional thread for logging, parsing, etc.</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;">msgMatch.AddPacket(msg);</p>
<p>That code should speak for itself; our <strong>MessageMatcher </strong>class will centralize message processing, and the <strong>AddPacket</strong> method is called for each server message. We do not filter client messages, because it seems that these originate mostly from the user&#8217;s actions (which are always known by the user –and must be confirmed by the server, regardless.)</p>
<p>Here, then, is the definition of the <strong>MessageMatcher </strong>class. Add it to your project (to the Eternal_Lands_Connector project, that is).</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;font-weight:normal;">using</span><span style="font-family:Courier New;font-size:10pt;font-weight:normal;"> System;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Collections.Generic;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Linq;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Threading;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Net.Sockets;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.IO;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">namespace</span><span style="font-family:Courier New;font-size:10pt;"> Eternal_Lands_Connector</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">class</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">MessageMatcher</span><span style="font-family:Courier New;font-size:10pt;"> : </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">SleepQueue</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#808080;font-family:Courier New;font-size:10pt;">///</span><span style="color:#008000;font-family:Courier New;font-size:10pt;"> </span><span style="color:#808080;font-family:Courier New;font-size:10pt;">&lt;summary&gt;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#808080;font-family:Courier New;font-size:10pt;">///</span><span style="color:#008000;font-family:Courier New;font-size:10pt;"> The core of our message matcher</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#808080;font-family:Courier New;font-size:10pt;">///</span><span style="color:#008000;font-family:Courier New;font-size:10pt;"> </span><span style="color:#808080;font-family:Courier New;font-size:10pt;">&lt;/summary&gt;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#808080;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Dictionary</span><span style="font-family:Courier New;font-size:10pt;">&lt;</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Int32</span><span style="font-family:Courier New;font-size:10pt;">, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">List</span><span style="font-family:Courier New;font-size:10pt;">&lt;MessageHandler&gt;&gt; handlers = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Dictionary</span><span style="font-family:Courier New;font-size:10pt;">&lt;</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Int32</span><span style="font-family:Courier New;font-size:10pt;">, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">List</span><span style="font-family:Courier New;font-size:10pt;">&lt;MessageHandler&gt;&gt;();</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> addHandler(MessageHandler h)</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (!handlers.ContainsKey(h.getProtocol()))</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">handlers[h.getProtocol()] = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">List</span><span style="font-family:Courier New;font-size:10pt;">&lt;MessageHandler&gt;();</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">handlers[h.getProtocol()].Add(h);</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Console</span><span style="font-family:Courier New;font-size:10pt;">.WriteLine(</span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">&#8220;Dictionary size: &#8220;</span><span style="font-family:Courier New;font-size:10pt;"> + handlers.Count + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">&#8221;   entries["</span><span style="font-family:Courier New;font-size:10pt;"> + h.getProtocol() + </span><span style="color:#a31515;font-family:Courier New;font-size:10pt;">"] &#8211;&gt; &#8220;</span><span style="font-family:Courier New;font-size:10pt;"> + handlers[h.getProtocol()].Count);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">AddToConsoleDel</span><span style="font-family:Courier New;font-size:10pt;"> UpdateConsole;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> On_Message(</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">PacketData</span><span style="font-family:Courier New;font-size:10pt;"> msg)</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (msg == </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">null</span><span style="font-family:Courier New;font-size:10pt;">)</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;">;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Now, segment into multiple messages</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">for</span><span style="font-family:Courier New;font-size:10pt;"> (</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> currID = 0; currID &lt; msg.data.Length; )</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> protocol = msg.data[currID++];</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> size = msg.data[currID++] | (msg.data[currID++] &lt;&lt; 8);</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Make a new data array</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> count = size &#8211; 1;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] b = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[count];</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Array</span><span style="font-family:Courier New;font-size:10pt;">.Copy(msg.data, currID, b, 0, count);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">currID += count;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Match the first relevant handler</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (handlers.ContainsKey(protocol))</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">foreach</span><span style="font-family:Courier New;font-size:10pt;"> (MessageHandler h </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">in</span><span style="font-family:Courier New;font-size:10pt;"> handlers[protocol])</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (h.performMatch(protocol, b, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">new</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Dictionary</span><span style="font-family:Courier New;font-size:10pt;">&lt;</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">string</span><span style="font-family:Courier New;font-size:10pt;">, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">object</span><span style="font-family:Courier New;font-size:10pt;">&gt;()))</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">break</span><span style="font-family:Courier New;font-size:10pt;">;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#808080;font-family:Courier New;font-size:10pt;">///</span><span style="color:#008000;font-family:Courier New;font-size:10pt;"> </span><span style="color:#808080;font-family:Courier New;font-size:10pt;">&lt;summary&gt;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#808080;font-family:Courier New;font-size:10pt;">///</span><span style="color:#008000;font-family:Courier New;font-size:10pt;"> Somwhat less-interesting features</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#808080;font-family:Courier New;font-size:10pt;">///</span><span style="color:#008000;font-family:Courier New;font-size:10pt;"> </span><span style="color:#808080;font-family:Courier New;font-size:10pt;">&lt;/summary&gt;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#808080;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> valid = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> IsValid</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">get</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> valid;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">set</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">valid = </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">value</span><span style="font-family:Courier New;font-size:10pt;">;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//We make this its own class so we can change its priority.</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> System.Threading.</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ThreadPriority</span><span style="font-family:Courier New;font-size:10pt;"> getInitialPriority()</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">ThreadPriority</span><span style="font-family:Courier New;font-size:10pt;">.BelowNormal;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> isValid()</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> valid;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> On_Thread_Close()</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Nothing to do here</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">protected</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> Pre_Init_Activity()</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Nothing to do here</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p>The <strong>MessageHandler </strong>class hasn&#8217;t been created yet, but let&#8217;s just say that it matches all messages first on a “protocol” and then on a more complex “performMatch” query. All of these <strong>MessageHandler</strong>s<strong> </strong>are stored indexed by protocol in a hash table. This ensures that we can add lots of processing handlers without slowing down the pattern matching.</p>
<p>Finally, note that <strong>MessageMatcher </strong>is a <strong>SleepQueue</strong>, which means that even if we do add far too many handlers of the same protocol (say, one for each buddy in our buddy list?), only our matching will be delayed –the core won&#8217;t be.</p>
<p>You might be wondering about the structure of <strong>Eternal Lands</strong>&#8216;s messages. From the processing loop in <strong>MessageMatcher</strong>, you can tell that every message contains a <strong>protocol </strong>byte as the first item in the message. The next two bytes describe the <strong>size </strong>of the remaining data. This is more important than you might think: Eternal Lands often sends multiple messages bunched together, and you can only tell where one ends and the next begins by processing the <strong>size </strong>bytes. Anything after the first three bytes is dependant on the protocol of the message. Also, for some unknowable reason, the <em>actual </em>size of the remaining data is <strong>size-1</strong>.</p>
<p>Now, make a class called <strong>MessageHandler</strong>, in the Eternal_Lands_Connector project:</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;">using</span><span style="font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;"> System;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Collections.Generic;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Linq;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">using</span><span style="font-family:Courier New;font-size:10pt;"> System.Text;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">namespace</span><span style="font-family:Courier New;font-size:10pt;"> Eternal_Lands_Connector</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">abstract</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">class</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">MessageHandler</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//All message handlers match on a protocol</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">abstract</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> getProtocol();</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Within a given protocol, does this handler match?</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//  This should also perform an action</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//  Decorations used to avoid multiple calculations</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">abstract</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> performMatch(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> protocol, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] data, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Dictionary</span><span style="font-family:Courier New;font-size:10pt;">&lt;</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">String</span><span style="font-family:Courier New;font-size:10pt;">, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Object</span><span style="font-family:Courier New;font-size:10pt;">&gt; decorations);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p>Were you to compile your project, you would notice that <strong>Form1</strong>&#8216;s call of <strong>middleWare.startAll()</strong> is missing an argument: <strong>MessageMatcher</strong>. Before we go passing in an empty class, let&#8217;s try thinking about the types of <strong>MessageHandlers </strong>we might need. Well, the most <strong>basic </strong>type will simply match based on the <strong>protocol</strong>, and defer further processing till later. Then, we might want to match <strong>text </strong>messages sent from the server, using such things as the color of the text, the channel it was sent to, and a regular expression of what the text itself must contain.</p>
<p>First, make a folder (in the main Forms project) called <strong>matching</strong>. We will put three classes in there: <strong>Constants.cs</strong>, <strong>BasicHandler.cs</strong>, and <strong>TextHandler.cs</strong>. First, let&#8217;s cover <strong>Constants.cs</strong>:</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;">public</span><span style="font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;">class</span><span style="font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;">Constants</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">enum</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Protocols</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">RAW_TEXT = 0,</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">SEND_PARTIAL_STAT = 49,</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">GET_NEW_INVENTORY_ITEM = 21,</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">enum</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Colors</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">c_green1 = 3,</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">c_red1 = 0,</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">enum</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Channels</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">CHAT_SERVER = 3,</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p>This class simply contains some useful constants used to identify channels, colors, and protocols. We&#8217;ve included only the bare minimum; please add any constants as your message matching needs expand.</p>
<p>Now, <strong>BasicHanlder.cs</strong>:</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;">class</span><span style="font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;">BasicHandler</span><span style="font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;"> : Eternal_Lands_Connector.</span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;font-style:normal;font-weight:normal;">MessageHandler</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">delegate</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">void</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">OnMatchDel</span><span style="font-family:Courier New;font-size:10pt;">(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] data);</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> protocol;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">private</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">OnMatchDel</span><span style="font-family:Courier New;font-size:10pt;"> OnMatch;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> BasicHandler(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> protocolMatch, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">OnMatchDel</span><span style="font-family:Courier New;font-size:10pt;"> OnMatch)</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.protocol = protocolMatch;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">this</span><span style="font-family:Courier New;font-size:10pt;">.OnMatch = OnMatch;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> getProtocol()</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> protocol;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">public</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">override</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">bool</span><span style="font-family:Courier New;font-size:10pt;"> performMatch(</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">int</span><span style="font-family:Courier New;font-size:10pt;"> protocol, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">byte</span><span style="font-family:Courier New;font-size:10pt;">[] data, </span><span style="color:#2b91af;font-family:Courier New;font-size:10pt;">Dictionary</span><span style="font-family:Courier New;font-size:10pt;">&lt;</span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">string</span><span style="font-family:Courier New;font-size:10pt;">, </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">object</span><span style="font-family:Courier New;font-size:10pt;">&gt; decorations)</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">{</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Quick initial match</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">if</span><span style="font-family:Courier New;font-size:10pt;"> (protocol != getProtocol())</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">false</span><span style="font-family:Courier New;font-size:10pt;">;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#008000;font-family:Courier New;font-size:10pt;">//Always match</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">OnMatch(data);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">return</span><span style="font-family:Courier New;font-size:10pt;"> </span><span style="color:#0000ff;font-family:Courier New;font-size:10pt;">true</span><span style="font-family:Courier New;font-size:10pt;">;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Calibri;"><span style="font-family:Courier New;font-size:10pt;">}</span></p>
<p>The unfortunate reality is that this class is so simple that it makes understanding it tricky. It&#8217;s very simple:</p>
<ol>
<li>The constructor takes a <strong>protocol </strong>value to match, and an <strong>OnMatch </strong>delegate to perform when that protocol matches. It saves these.</li>
<li>The <strong>getProtocol()</strong> method exists so that our MessageMatcher can store this MessageHandler in the correct hash table entry.</li>
<li>The <strong>performMatch()</strong> function always returns true, after performing the <strong>OnMatch </strong>delegate, assuming the protocol byte matches.</li>
</ol>
<p>Without thinking too much about it, let&#8217;s add the code for <strong>TextHandler.cs</strong> and compare the two:</p>
<p style="font-size:12pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;"><span style="color:#0000ff;font-size:10pt;">public</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">class</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">TextMessage</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">public</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> channel;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">public</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> color;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">public</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">String</span><span style="font-size:10pt;"> text;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">public</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">class</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">TextHandler</span><span style="font-size:10pt;"> : Eternal_Lands_Connector.</span><span style="color:#2b91af;font-size:10pt;">MessageHandler</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">const</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">String</span><span style="font-size:10pt;"> KEY_DECORATIONS = </span><span style="color:#a31515;font-size:10pt;">&#8220;TextHandler_Decorations&#8221;</span><span style="font-size:10pt;">;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">public</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">delegate</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">void</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">OnMatchDel</span><span style="font-size:10pt;">(</span><span style="color:#2b91af;font-size:10pt;">TextMessage</span><span style="font-size:10pt;"> m);</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Regex</span><span style="font-size:10pt;"> msgPattern;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> msgColor;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> msgChannel;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">OnMatchDel</span><span style="font-size:10pt;"> OnMatch;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//-1 for &#8220;all&#8221; on color or channel</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">public</span><span style="font-size:10pt;"> TextHandler(</span><span style="color:#2b91af;font-size:10pt;">String</span><span style="font-size:10pt;"> msgPattern, </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> color, </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> channel, </span><span style="color:#2b91af;font-size:10pt;">OnMatchDel</span><span style="font-size:10pt;"> OnMatch)</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">this</span><span style="font-size:10pt;">.msgPattern = </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Regex</span><span style="font-size:10pt;">(msgPattern);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">this</span><span style="font-size:10pt;">.msgColor = color;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">this</span><span style="font-size:10pt;">.msgChannel = channel;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">this</span><span style="font-size:10pt;">.OnMatch = OnMatch;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">public</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">override</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> getProtocol()</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">return</span><span style="font-size:10pt;"> (</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;">)</span><span style="color:#2b91af;font-size:10pt;">Protocols</span><span style="font-size:10pt;">.RAW_TEXT;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">public</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">override</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">bool</span><span style="font-size:10pt;"> performMatch(</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> protocol, </span><span style="color:#0000ff;font-size:10pt;">byte</span><span style="font-size:10pt;">[] data, </span><span style="color:#2b91af;font-size:10pt;">Dictionary</span><span style="font-size:10pt;">&lt;</span><span style="color:#2b91af;font-size:10pt;">String</span><span style="font-size:10pt;">, </span><span style="color:#2b91af;font-size:10pt;">Object</span><span style="font-size:10pt;">&gt; decorations)</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Quick check; protocol</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">if</span><span style="font-size:10pt;"> (protocol != getProtocol())</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">return</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">false</span><span style="font-size:10pt;">;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Get</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">if</span><span style="font-size:10pt;"> (!decorations.ContainsKey(KEY_DECORATIONS))</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Construct</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#2b91af;font-size:10pt;">TextMessage</span><span style="font-size:10pt;"> t = </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">TextMessage</span><span style="font-size:10pt;">();</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">t.channel = data[0];</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">t.color = data[1] &#8211; 127;</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Parse Text</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> count = data.Length &#8211; 2;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;">t.text = System.Text.</span><span style="color:#2b91af;font-size:10pt;">ASCIIEncoding</span><span style="font-size:10pt;">.ASCII.GetString(data, 2, count);</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Later, of course, we&#8217;ll have to deal with things like embedded color tags, etc.</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#008000;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Save</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">decorations[KEY_DECORATIONS] = t;</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#2b91af;font-size:10pt;">TextMessage</span><span style="font-size:10pt;"> message = (</span><span style="color:#2b91af;font-size:10pt;">TextMessage</span><span style="font-size:10pt;">)decorations[KEY_DECORATIONS];</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Match -Stage 1</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">if</span><span style="font-size:10pt;"> ((msgChannel != -1 &amp;&amp; message.channel != msgChannel) || (msgColor != -1 &amp;&amp; message.color != msgColor))</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">return</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">false</span><span style="font-size:10pt;">;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Does the text match?</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">if</span><span style="font-size:10pt;"> (!msgPattern.IsMatch(message.text))</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">return</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">false</span><span style="font-size:10pt;">;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//It matches!</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">OnMatch(message);</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">return</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">true</span><span style="font-size:10pt;">;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.1402in;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p>You&#8217;ll notice that I didn&#8217;t include the <strong>using </strong>directives or the enclosing <strong>namespace</strong>. Whatever Visual Studio provides as defaults will work in this case. You&#8217;ll have to add two additional <strong>using </strong>directives, however. Note the second one; it <a href="http://msdn.microsoft.com/en-us/library/sf0df423%28VS.80%29.aspx"><span style="color:#0000ff;"><strong>assigns an alias</strong></span></a> to an enum within our <strong>Constants </strong>class. This allows us to simply reference <strong>Protocols.RAW_TEXT</strong>, instead of the more cumbersome <strong>Constants.Protocols.RAW_TEXT</strong>.</p>
<p style="font-size:12pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;"><span style="color:#0000ff;font-size:10pt;">using</span><span style="font-size:10pt;"> System.Text.RegularExpressions;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">using</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Protocols</span><span style="font-size:10pt;"> = WindowsFormsApplication1.matching.</span><span style="color:#2b91af;font-size:10pt;">Constants</span><span style="font-size:10pt;">.</span><span style="color:#2b91af;font-size:10pt;">Protocols</span><span style="font-size:10pt;">;</span></p>
<p>We&#8217;re now ready to create some message handlers and log their output. Go to your main form&#8217;s <strong>ConnectToServer</strong> method, and add the following lines after your various checks for “Started”</p>
<p style="font-size:12pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;"><span style="color:#008000;font-size:10pt;">//Make a Message Matcher to handle all our special cases</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#2b91af;font-size:10pt;">MessageMatcher</span><span style="font-size:10pt;"> match = </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">MessageMatcher</span><span style="font-size:10pt;">();</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">match.UpdateConsole = UpdateConsole;</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Add some filters</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#2b91af;font-size:10pt;">TextHandler</span><span style="font-size:10pt;"> h1 = </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">TextHandler</span><span style="font-size:10pt;">(</span><span style="color:#a31515;font-size:10pt;">&#8220;You stopped harvesting.&#8221;</span><span style="font-size:10pt;">, (</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;">)</span><span style="color:#2b91af;font-size:10pt;">Colors</span><span style="font-size:10pt;">.c_red1, (</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;">)</span><span style="color:#2b91af;font-size:10pt;">Channels</span><span style="font-size:10pt;">.CHAT_SERVER, </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">TextHandler</span><span style="font-size:10pt;">.</span><span style="color:#2b91af;font-size:10pt;">OnMatchDel</span><span style="font-size:10pt;">(On_Harvest_Stop));</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">match.addHandler(h1);</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#2b91af;font-size:10pt;">BasicHandler</span><span style="font-size:10pt;"> h2 = </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">BasicHandler</span><span style="font-size:10pt;">((</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;">)</span><span style="color:#2b91af;font-size:10pt;">Protocols</span><span style="font-size:10pt;">.GET_NEW_INVENTORY_ITEM, </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">BasicHandler</span><span style="font-size:10pt;">.</span><span style="color:#2b91af;font-size:10pt;">OnMatchDel</span><span style="font-size:10pt;">(Got_Item));</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;">match.addHandler(h2);</p>
<p>You will also need some <strong>using </strong>directives:</p>
<p style="font-size:12pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;"><span style="color:#0000ff;font-size:10pt;">using</span><span style="font-size:10pt;"> WindowsFormsApplication1.matching;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">using</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Protocols</span><span style="font-size:10pt;"> = WindowsFormsApplication1.matching.</span><span style="color:#2b91af;font-size:10pt;">Constants</span><span style="font-size:10pt;">.</span><span style="color:#2b91af;font-size:10pt;">Protocols</span><span style="font-size:10pt;">;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">using</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Colors</span><span style="font-size:10pt;"> = WindowsFormsApplication1.matching.</span><span style="color:#2b91af;font-size:10pt;">Constants</span><span style="font-size:10pt;">.</span><span style="color:#2b91af;font-size:10pt;">Colors</span><span style="font-size:10pt;">;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">using</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Channels</span><span style="font-size:10pt;"> = WindowsFormsApplication1.matching.</span><span style="color:#2b91af;font-size:10pt;">Constants</span><span style="font-size:10pt;">.</span><span style="color:#2b91af;font-size:10pt;">Channels</span><span style="font-size:10pt;">;</span></p>
<p>&#8230;the “WindowsFormsApplication1” should be the name of your project; you should be able to resolve naming conflicts like this on your own. Finally, add your <strong>MessageMatcher </strong>into the call to <strong>startAll</strong>:</p>
<p style="font-size:12pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;"><span style="font-size:10pt;">middleWare.startAll(srv, match, loopbackInfo, txtPathToELFolder.Text, </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">ShowConnectMsgDel</span><span style="font-size:10pt;">(ShowConnectMsg), </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">AddToConsoleDel</span><span style="font-size:10pt;">(UpdateConsole), </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">IncrPacketCountDel</span><span style="font-size:10pt;">(IncrPacketCount), </span><span style="color:#2b91af;font-size:10pt;">Thread</span><span style="font-size:10pt;">.CurrentThread.ManagedThreadId);</span></p>
<p>The only thing left to do is to implement <strong>On_Harvest_Stop</strong> and <strong>Got_Item</strong>. Here are the methods:</p>
<p style="font-size:12pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;"><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">void</span><span style="font-size:10pt;"> On_Harvest_Stop(</span><span style="color:#2b91af;font-size:10pt;">TextMessage</span><span style="font-size:10pt;"> tm)</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Show message:</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;">UpdateConsole(</span><span style="color:#a31515;font-size:10pt;">&#8220;\r\nYou have stopped harvesting.&#8221;</span><span style="font-size:10pt;">);</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">void</span><span style="font-size:10pt;"> Got_Item(</span><span style="color:#0000ff;font-size:10pt;">byte</span><span style="font-size:10pt;">[] data)</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Decode our message</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> image_id = data[0] | (data[1]&lt;&lt;8);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> quantity = data[2] | (data[3]&lt;&lt;8) | (data[4]&lt;&lt;16) | (data[5]&lt;&lt;32);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> pos = data[6];</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">uint</span><span style="font-size:10pt;"> flags = data[7];</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#008000;font-size:10pt;">//Show message:</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;">UpdateConsole(</span><span style="color:#a31515;font-size:10pt;">&#8220;\r\nYou got &#8220;</span><span style="font-size:10pt;"> + quantity + </span><span style="color:#a31515;font-size:10pt;">&#8221; item(s): &#8220;</span><span style="font-size:10pt;"> + image_id);</span></p>
<p>The <strong>On_Harvest_Stop</strong> method simply informs the player that he or she has stopped harvesting. At this point, all we have to do is show a window and we&#8217;d be at <a href="http://lthzelda.wordpress.com/2009/04/11/el-1-game-event-notifier/"><span style="color:#0000ff;"><strong>the same point we were with the previous approach</strong></span></a>. (We&#8217;ll spice that up in the next tutorial). The <strong>Got_Item</strong> method gets the<strong> image_id</strong>, <strong>quantity</strong>, <strong>position</strong>, and <strong>flags </strong>for the item the user picked up (through harvesting, from a drop bag, whatever) and informs the user of these values. We&#8217;ll expand on this in the next section. How do we get this data? Read the<strong> Eternal Lands</strong> source code –it&#8217;s pretty easy to find what you want. For example, a little digging reveals the purpose of the <strong>flags </strong>byte:</p>
<p style="font-size:12pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;"><span style="font-size:10pt;">is_resource        = binary(0010)  //Can be used to manufacture</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">is_reagent         = binary(0001)  //Can be used in magic</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">use_with_inventory = binary(1000)  //Item can be used with inventory</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">is_stackable       = binary(0100)  //The item is stackable</p>
<p>Moving on, compile and run your code, log in to the main server, and harvest something. Alt+Tab to our C# window and wait for the “You have stopped harvesting” message. Useful, eh? You&#8217;ll also see some “Got Item” messages.</p>
<div id="attachment_238" class="wp-caption alignnone" style="width: 157px"><a href="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_both_filters_work.png"><img class="size-medium wp-image-238" title="post_9_pt1_both_filters_work" src="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_both_filters_work.png?w=147&#038;h=224" alt="post_9_pt1_both_filters_work" width="147" height="224" /></a><p class="wp-caption-text">Several Item and Harvest Messages</p></div>
<p>You should take some time to study these messages. First of all, you&#8217;ll notice that the <strong>quantity </strong>of a “got” item is the <em>total </em>number you now have, not the number you just picked up. Second, you&#8217;ll see that one of the items we were harvesting (id 35) was harvested at 2x the normal rate. This is because we were at one of the 2x spots for that item.</p>
<p><strong>Step 5: Bonus! Fun With Images</strong></p>
<p>At this point, we&#8217;re basically done with phase one of our project. We can hook the server and filter messages by a variety of criteria (without recompiling the connection code). But before we call it quits, there&#8217;s one thing that&#8217;s bothering me: what exactly is item 35? Unfortunately, there&#8217;s no easy way to tell, as the <strong>Eternal Lands</strong> client simply deals with images and identifiers. But maybe we can at least show a picture of the item we just picked up?</p>
<p>If you dig a bit in the source code, you&#8217;ll find that the following code is used for drawing items:</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">cur_item_img=item_list[pos].image_id%25;</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">u_start=0.2f*(cur_item_img%5);</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">u_end=u_start+(float)50/256;</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">v_start=(1.0f+((float)50/256)/256.0f)-((float)50/256*(cur_item_img/5));</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">v_end=v_start-(float)50/256;</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">//get the texture this item belongs to</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">this_texture=get_items_texture(item_list[pos].image_id/25);</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">get_and_set_texture_id(this_texture);</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">glBegin(GL_QUADS);</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">if(mini)</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">draw_2d_thing(u_start,v_start,u_end,v_end,mouse_x-16,mouse_y-16,mouse_x+16,mouse_y+16);</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">else</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">draw_2d_thing(u_start,v_start,u_end,v_end,mouse_x-25,mouse_y-25,mouse_x+25,mouse_y+25);</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">glEnd();</p>
<p>Converting this to pseudo-code, we get:</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">image_id = curr_item_img + (25*item_texture_num)</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">curr_item_img = u_comp + (5*v_comp)</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">u_start = 0.2*u_comp</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">u_end = u_start + 0.195  //Width is roughly in .2 increments</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">v_start = 1.00076 &#8211; 0.195 * v_comp</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">v_end = v_start &#8211; 0.195</p>
<p>A shrewd observer (or one accustomed to OpenGL) will notice that this code assumes Cartesian coordinates, so we&#8217;d have to flip the<strong> v_*</strong> variables.</p>
<p>Before we convert this to C#, browse to the <strong>Eternal Lands</strong> directory, and look in the “textures” sub-folder. Then, look at any of the “<strong>items*.bmp</strong>” files. Hmm&#8230; these images look mighty familiar&#8230;</p>
<div id="attachment_240" class="wp-caption alignnone" style="width: 175px"><a href="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_items3.png"><img class="size-full wp-image-240" title="post_9_pt1_items3" src="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_items3.png?w=500" alt="post_9_pt1_items3"   /></a><p class="wp-caption-text">A 5x5 Grid of Eternal Lands Items</p></div>
<p>Here&#8217;s the code to open one of these 5&#215;5 <strong>items </strong>files, and read each separate image into a <strong>Bitmap </strong>object. Add this to your main Form&#8217;s <strong>ReadELFiles </strong>method, right before setting <strong>cmbServers.Enabled</strong> to <strong>true</strong>.</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#008000;font-style:normal;font-weight:normal;">//Now load our bitmaps from the textures folder</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="color:#0000ff;font-size:10pt;">for</span><span style="font-size:10pt;"> (</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> img_texture_id = 0; </span><span style="color:#0000ff;font-size:10pt;">true</span><span style="font-size:10pt;">; img_texture_id++)</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#008000;font-size:10pt;">//Load this image</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">String</span><span style="font-size:10pt;"> path = txtPathToELFolder.Text + </span><span style="color:#a31515;font-size:10pt;">&#8220;\\&#8221;</span><span style="font-size:10pt;"> + </span><span style="color:#a31515;font-size:10pt;">&#8220;textures&#8221;</span><span style="font-size:10pt;"> + </span><span style="color:#a31515;font-size:10pt;">&#8220;\\&#8221;</span><span style="font-size:10pt;"> + </span><span style="color:#a31515;font-size:10pt;">&#8220;items&#8221;</span><span style="font-size:10pt;"> + (img_texture_id + 1) + </span><span style="color:#a31515;font-size:10pt;">&#8220;.bmp&#8221;</span><span style="font-size:10pt;">;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">if</span><span style="font-size:10pt;"> (!</span><span style="color:#2b91af;font-size:10pt;">File</span><span style="font-size:10pt;">.Exists(path))</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">break</span><span style="font-size:10pt;">;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Bitmap</span><span style="font-size:10pt;"> patch = </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Bitmap</span><span style="font-size:10pt;">(path);</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#008000;font-size:10pt;">//Loop through all possible images</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">for</span><span style="font-size:10pt;"> (</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> curr_item_img = 0; curr_item_img &lt; 25; curr_item_img++)</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#008000;font-size:10pt;">//Construct a composite id</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> composite_id = curr_item_img + 25 * img_texture_id;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#008000;font-size:10pt;">//Get the sub-images&#8217; co-ordinates</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">float</span><span style="font-size:10pt;"> u_start = 0.2F * (curr_item_img % 5);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">float</span><span style="font-size:10pt;"> u_end = u_start + (</span><span style="color:#0000ff;font-size:10pt;">float</span><span style="font-size:10pt;">)50 / 256;</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">float</span><span style="font-size:10pt;"> v_start = (1.0f + ((</span><span style="color:#0000ff;font-size:10pt;">float</span><span style="font-size:10pt;">)50 / 256) / 256.0f) &#8211; ((</span><span style="color:#0000ff;font-size:10pt;">float</span><span style="font-size:10pt;">)50 / 256 * (curr_item_img / 5));</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">float</span><span style="font-size:10pt;"> v_end = v_start &#8211; (</span><span style="color:#0000ff;font-size:10pt;">float</span><span style="font-size:10pt;">)50 / 256;</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#008000;font-size:10pt;">//Convert to pixels, non-Cartesian</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> xStart = (</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;">)(u_start * 256);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> xEnd = (</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;">)(u_end * 256);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> yStart = 256 &#8211; (</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;">)(v_start * 256);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> yEnd = 256 &#8211; (</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;">)(v_end * 256);</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#008000;font-size:10pt;">//Draw this into its own bitmap</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Bitmap</span><span style="font-size:10pt;"> pic = </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Bitmap</span><span style="font-size:10pt;">(xEnd &#8211; xStart, yEnd &#8211; yStart);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Graphics</span><span style="font-size:10pt;"> g = </span><span style="color:#2b91af;font-size:10pt;">Graphics</span><span style="font-size:10pt;">.FromImage(pic);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> g.DrawImage(patch, </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Rectangle</span><span style="font-size:10pt;">(0, 0, xEnd &#8211; xStart, yEnd &#8211; yStart), </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Rectangle</span><span style="font-size:10pt;">(xStart, yStart, xEnd &#8211; xStart, yEnd &#8211; yStart), </span><span style="color:#2b91af;font-size:10pt;">GraphicsUnit</span><span style="font-size:10pt;">.Pixel);</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">itemPics[composite_id] = pic;</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p>The code is pretty self-explanatory; it simply reads all<strong> items*.bmp</strong> files until one doesn&#8217;t exist. For each of the 25 items, it applies the segmentation algorithm. It does require one more variable, added at the top of the class:</p>
<p style="font-size:12pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;"><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Dictionary</span><span style="font-size:10pt;">&lt;</span><span style="color:#2b91af;font-size:10pt;">Int32</span><span style="font-size:10pt;">, </span><span style="color:#2b91af;font-size:10pt;">Bitmap</span><span style="font-size:10pt;">&gt; itemPics = </span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">Dictionary</span><span style="font-size:10pt;">&lt;</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;">, </span><span style="color:#2b91af;font-size:10pt;">Bitmap</span><span style="font-size:10pt;">&gt;();</span></p>
<p>Now, let&#8217;s use this! Add the following code to the end of <strong>Got_Item</strong>, replacing the existing call to <strong>UpdateConsole</strong>:</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;font-weight:normal;">UpdateGotImage(image_id);</p>
<p>Now, implement our delegate and method call, as usual:</p>
<p style="font-size:12pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:normal;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">delegate</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">void</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">UpdateGotImageDel</span><span style="font-size:10pt;">(</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> image_id);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">private</span><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">void</span><span style="font-size:10pt;"> UpdateGotImage(</span><span style="color:#0000ff;font-size:10pt;">int</span><span style="font-size:10pt;"> image_id)</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">if</span><span style="font-size:10pt;"> (justGotItem.InvokeRequired)</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> justGotItem.Invoke(</span><span style="color:#0000ff;font-size:10pt;">new</span><span style="font-size:10pt;"> </span><span style="color:#2b91af;font-size:10pt;">UpdateGotImageDel</span><span style="font-size:10pt;">(UpdateGotImage), image_id);</span></p>
<p style="font-size:11pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;"><span style="font-size:10pt;"> </span><span style="color:#0000ff;font-size:10pt;">else</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">{</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">justGotItem.Image = itemPics[image_id];</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p style="font-size:10pt;line-height:115%;margin-bottom:.139in;margin-top:0;text-align:left!important;font-family:Courier New;">}</p>
<p>This references a GUI component that doesn&#8217;t exist yet. Add a <strong>PictureBox </strong>to your Form (anywhere it fits) and set its <strong>name </strong>to <strong>justGotItem </strong>and its <strong>size </strong>to <strong>50,50</strong>. Sorry for approaching this in a rather roundabout fashion, but I&#8217;m sure you were able to keep up. Compile and run your code. Now, pay attention to your C# window every time you get a new item.</p>
<div id="attachment_239" class="wp-caption alignnone" style="width: 204px"><a href="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_catching_roses.png"><img class="size-medium wp-image-239" title="post_9_pt1_catching_roses" src="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_catching_roses.png?w=194&#038;h=170" alt="post_9_pt1_catching_roses" width="194" height="170" /></a><p class="wp-caption-text">Harvesting Roses; Game Proves It&#39;s Working</p></div>
<p>Proof that this actually works is somehow so much more satisfying once images are involved. I&#8217;m at a loss to explain it.</p>
<p>The possibilities from here on in are really endless. What about catching <strong>Private Messages</strong> from players, and funneling them into GTalk through their API? How about updating your <strong>Eternal Lands</strong> blog with the item you are harvesting or making, in real-time? What about saving the value returned each time you use an<strong> Astrology Indicator</strong>, and then charting the results to see how your luck fares over time? All of these things are possible, and none (as near as I can tell) violate the terms of use of Eternal Lands. But make sure you <a href="http://www.eternal-lands.com/forum/"><span style="color:#0000ff;"><strong>post on the EL forum</strong></span></a>, if you&#8217;re not sure. It&#8217;s better to get permission rather than get banned.</p>
<p>I regret that I&#8217;ve only posted half the code I&#8217;ve written at this point. It just takes<em> so long</em> to re-write and re-test everything. I&#8217;m a bit tired of all this right now; next time I feel like writing 50 pages of text, though, I&#8217;ll finally show you how to soup up your message interface. Consider the following screenshots as teasers. Note the cool “dissolve in” effect, and the “maximize” and “close” buttons (I edited the image; normally they only highlight when you mouse over them.) All of this code works; I just need to document it, and hook up the notifications to real messages (no, I did not get three enrichment stones in a row. <img src='http://s2.wp.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  )</p>
<div id="attachment_242" class="wp-caption alignnone" style="width: 240px"><a href="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_system_tray.png"><img class="size-medium wp-image-242" title="post_9_pt1_system_tray" src="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_system_tray.png?w=230&#038;h=99" alt="post_9_pt1_system_tray" width="230" height="99" /></a><p class="wp-caption-text">Nice System Tray Icon</p></div>
<div id="attachment_241" class="wp-caption alignnone" style="width: 224px"><a href="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_message_stack.png"><img class="size-medium wp-image-241" title="post_9_pt1_message_stack" src="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_message_stack.png?w=214&#038;h=134" alt="post_9_pt1_message_stack" width="214" height="134" /></a><p class="wp-caption-text">Version 2.0 Has a Fancy, Animating Notification Stack</p></div>
<p><strong>Final Discussion </strong></p>
<p><strong>Eternal Lands</strong> is one of my favorite online games, and yet like all cross-platform games, it doesn&#8217;t feel tightly integrated into Windows. One benefit of them opening the source to developers is that we can now hack around and improve the code as we see fit, distributing our changes to benefit everyone. In this article, I showed you how to enhance the notifications provided by <strong>Eternal Lands</strong>, to make harvesting of high-level items less tedious. By using a high-level language (C#) with low-level hooks into <strong>Win32 </strong>networking, we achieve both power and speed, with the potential to add nice animations and <strong>Windows</strong>-specific polish as well. Best of luck with your own hacks!</p>
<p><strong>License &#8211; Preamble</strong></p>
<p>The current code cannot be used to abuse the terms of use of <strong>Eternal Lands</strong>, and I&#8217;ve chosen a carefully-worded license to prevent further modifications of this code from being used for abuse. The<strong> Eternal Lands</strong> developers trusted us with their code, and I intend to honor that trust. Please do the same. The following license applies to source code, compiled binaries, and this article, describing how to make the program from scratch. All future source and binary releases (as well as updates to this article) will remain under this license.</p>
<p><strong>License</strong></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;">Copyright (c) 2009 Seth N. Hetu</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;"> </span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;">Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &#8220;Software&#8221;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;"> </span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;">The Software may not be modified to abuse the Terms and Conditions of the Eternal Lands game, as expressed in its license (http://www.eternal-lands.com/page/license.txt).</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;"> </span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;">The Software may not be used to inject events to, nor remove messages from, the regular stream of packets sent between the Eternal Lands client and the Eternal Lands server. </span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;"> </span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;">All messages sent from the Eternal Lands client to the Eternal Lands server and vice-versa must arrive at their intended destinations without delay and without reordering or modifying them.</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;"> </span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;">The Thread Priority of the event handler used by the Software may not be modified; moreover, any threads created that interact with the Software in any way MUST have a lower Thread Priority than that of the event handler.</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;"> </span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;">If, at any time, an Eternal Lands moderator (as listed at: http://www.eternal-lands.com/page/developers.php?#mods) or Eternal Lands creator (http://www.eternal-lands.com/page/developers.php?#creators) requests that the Software or any specific derivative work be removed, for any reason, this demand must be met, and all source code and compiled code for the Software must be removed from public display. (Aside: We would ask moderators to be reasonable when demanding that the Software be removed.) The Software and its sources may be restored to public display only with the permission of an Eteranl Lands moderator. In the case of a dispute between moderators and creators, the creators are given preference.</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;"> </span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;">The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;"> </span></p>
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;">
<p style="font-size:10pt;line-height:115%;margin-bottom:0;margin-top:0;text-align:left!important;font-family:Courier New;color:#000000;font-style:normal;text-decoration:none!important;font-weight:bold;"><span style="font-weight:normal;">THE SOFTWARE IS PROVIDED &#8220;AS IS&#8221;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, </span><span style="font-weight:normal;">FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</span></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/214/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/214/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/214/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/214/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/214/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/214/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/214/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/214/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/214/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/214/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/214/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/214/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/214/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/214/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=214&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2009/11/03/el-2-eternal-lands-tray-notifier-%e2%80%93-part-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_quick_vcs_intro.png?w=300" medium="image">
			<media:title type="html">post_9_pt1_quick_vcs_intro</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_initial_component_layout.png?w=300" medium="image">
			<media:title type="html">post_9_pt1_initial_component_layout</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_event_triggers_button.png?w=300" medium="image">
			<media:title type="html">post_9_pt1_event_triggers_button</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_loading_the_servers_file.png?w=260" medium="image">
			<media:title type="html">post_9_pt1_loading_the_servers_file</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/09/post_9_pt1_first_two_messages.png?w=260" medium="image">
			<media:title type="html">post_9_pt1_first_two_messages</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/10/post_9_pt1_cross_the_streams.png?w=300" medium="image">
			<media:title type="html">post_9_pt1_cross_the_streams</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_both_filters_work.png?w=260" medium="image">
			<media:title type="html">post_9_pt1_both_filters_work</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_items3.png" medium="image">
			<media:title type="html">post_9_pt1_items3</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_catching_roses.png?w=300" medium="image">
			<media:title type="html">post_9_pt1_catching_roses</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_system_tray.png?w=300" medium="image">
			<media:title type="html">post_9_pt1_system_tray</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/11/post_9_pt1_message_stack.png?w=300" medium="image">
			<media:title type="html">post_9_pt1_message_stack</media:title>
		</media:content>
	</item>
		<item>
		<title>[LZ-3] Intermediate Hyrule Magic</title>
		<link>http://lthzelda.wordpress.com/2009/06/24/lz-3-intermediate-hyrule-magic/</link>
		<comments>http://lthzelda.wordpress.com/2009/06/24/lz-3-intermediate-hyrule-magic/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 08:13:59 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=169</guid>
		<description><![CDATA[Blog Info: Staffman of the week goes to either Ubuntu or Fedora —whichever OS decided to corrupt the first block of this file, forcing me to re-type the entire thing. Back-story: Sometimes there&#8217;s no quaint little project (like LZ-2) that &#8230; <a href="http://lthzelda.wordpress.com/2009/06/24/lz-3-intermediate-hyrule-magic/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=169&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em><strong>Blog Info:</strong> Staffman of the week goes to either Ubuntu or Fedora —whichever OS decided to corrupt the first block of this file, forcing me to re-type the <strong>entire</strong> thing.</em></p>
<p><strong><em>Back-story:</em></strong> Sometimes there&#8217;s no quaint little project (like <a href="http://lthzelda.wordpress.com/2009/03/19/lz-2-bow-arrow-quest/"><strong><span style="color:#0000ff;">LZ-2</span></strong></a>) that gets you involved in the software; you just have to force yourself to accomplish stock goals. That&#8217;s what we&#8217;ll be doing in today&#8217;s lesson: solving a series of moderately difficult, realistically useful tasks related to Zelda hacking.</p>
<p><strong><em>Goal:</em></strong> Walk through some typical usage scenarios with Hyrule Magic.</p>
<p>Don’t forget your hash:<br />
<code style="color:black;">1a74468291b02729329dd1357afb45af <span style="color:#ff0000;"><strong>*Zelda3.smc</strong></span></code></p>
<h3><strong>Table Of Contents<br />
</strong></h3>
<p>1. <a href="#Question1"><span style="color:#0000ff;"><strong>How Do I Edit “Link’s Graphics” In Hyrule Magic?</strong></span></a></p>
<p>2. <a href="#Question2"><span style="color:#0000ff;"><strong>How Do I Save An Image in 16-Color Format?</strong></span></a></p>
<p>3. <a href="#Question3"><span style="color:#0000ff;"><strong>How Do I Edit Other Graphics? How Do I Use Zcompress and YY-CHR?</strong></span></a></p>
<p>4. <a href="#Question4"><span style="color:#0000ff;"><strong>How Do I Edit Overworld Tiles? What’s This 16&#215;16 Tile Nonsense?</strong></span></a></p>
<p>5. <strong>Lunch~</strong></p>
<p>6. <a href="#Question5"><span style="color:#0000ff;"><strong>How Do I Change Flute Locations?</strong></span></a></p>
<p>7. <a href="#Question6"><span style="color:#0000ff;"><strong>How Do I Edit The Game’s 3-D Graphics? How Complex Can These Graphics Be?</strong></span></a></p>
<p>8. <a href="#Question7"><span style="color:#0000ff;"><strong>How Do I Change The Music For An Area?</strong></span></a></p>
<p>9. <a href="#Question8"><span style="color:#0000ff;"><strong>How Do I Make An Enemy Drop a Key? How Do I Choose Which Enemy Drops the Key?</strong></span></a></p>
<p>10. <a href="#Question9"><span style="color:#0000ff;"><strong>How Do I Add a Nifty Logo To The Title Screen?</strong></span></a></p>
<p>11. <a href="#QuestionB"><span style="color:#0000ff;"><strong>(Bonus) How Do I Actually Manage a Large Project?</strong></span></a></p>
<p>12. <a href="#Add1"><span style="color:#0000ff;"><strong>Addendum: How do I make a number of torches open a door when lit and make them burn out after a period of time if I do not do light them fast enough?</strong></span></a></p>
<p>13. <a href="#Add2"><span style="color:#0000ff;"><strong>Addendum: How do I change were link lands when he falls in a hole to a lower level?</strong></span></a></p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Question1"><strong>Question: How Do I Edit “Link’s Graphics” In Hyrule Magic?</strong></a></h3>
<p>One of the latest additions to Hyrule Magic is a “Link’s Graphics” tab which gives you access to the 4bpp image data associated with our hero. It’s a bit tricky to use properly, though.</p>
<div id="attachment_147" class="wp-caption alignnone" style="width: 269px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_links_graphics.png"><img class="size-medium wp-image-147" title="post8_links_graphics" src="http://lthzelda.files.wordpress.com/2009/06/post8_links_graphics.png?w=259&#038;h=192" alt="Exporting Link's Graphics. Palette is Somewhat Messed Up, Since We're Using Wine. But It Should Work Ok." width="259" height="192" /></a><p class="wp-caption-text">Exporting Link&#39;s Graphics. Palette is Somewhat Messed Up, Since We&#39;re Using Wine. But It Should Still Work Ok.</p></div>
<p>The poses on the left are Link’s animation graphics, and the squares on the right are potential palettes. (You can click on various squares to mess with Link’s graphics, but make sure you click on the lower-left most square before doing any serious work.) To export graphics click the “copy” button, and then go to your favorite image editor and choose “paste”.</p>
<p>You might want to do this in Windows for two reasons. First, although Link’s palette (the bottom row) is shown properly in Wine, all other palette colors are messed up. Although the graphics editor doesn&#8217;t directly handle palette data, I personally wouldn&#8217;t risk having Wine corrupt your project; Hyrule Magic does enough corruption on its own. Second, <a href="http://www.getpaint.net/"><span style="color:#0000ff;"><strong>one of the best</strong></span></a> free raster editing programs for Windows has only spotty success under Wine. On Linux, I’ve yet to find a native equivalent —I consider The Gimp to be terrible for pixel-based editing. Either way, you’re on your own for <em><strong>how </strong></em>you edit the copied graphics. Just make sure you save your file as a 4-bit (16-color) BMP file. If you’re using an editor that doesn’t support 4bit BMPs, just save it as a True Color BMP and then convert it later (see the next question).</p>
<p>Let’s give Link a diving-style helmet when he swims. Simply edit the three side-facing and two forward-facing heads with water around them. Give Link the helmet, and also remove the “mouth opening” graphics, like so:</p>
<div id="attachment_152" class="wp-caption alignnone" style="width: 201px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_my_link_helmet.png"><img class="size-medium wp-image-152" title="post8_my_link_helmet" src="http://lthzelda.files.wordpress.com/2009/06/post8_my_link_helmet.png?w=191&#038;h=138" alt="Some of Link's Graphics, Edited to Add a Helmet. Background Faded For Emphasis" width="191" height="138" /></a><p class="wp-caption-text">Some of Link&#39;s Graphics, Edited to Add a Helmet. (Background Faded For Emphasis.)</p></div>
<p>Make sure that when you edit these graphics, you don’t use any new colors. <em><strong>Only</strong></em> use colors that are already in Link’s graphics. When you’re done, perform a “Select All” and then a “copy” from your image editor, then go into Hyrule Magic and choose “Paste” from the “Link’s Graphics” window. Save your game, and try it out.</p>
<div id="attachment_148" class="wp-caption alignnone" style="width: 242px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_link_swims.png"><img class="size-medium wp-image-148" title="post8_link_swims" src="http://lthzelda.files.wordpress.com/2009/06/post8_link_swims.png?w=232&#038;h=201" alt="Link Is Swimming With His New Safety Helmet On." width="232" height="201" /></a><p class="wp-caption-text">Link Is Swimming With His New Safety Helmet On.</p></div>
<p>It’s not perfect (several more graphics need to be changed to make the animation accurate), but it shows the concept.</p>
<p>If Link’s colors are messed up, or if you got the following error when you pasted in Link’s graphics, then you probably failed to save the image in proper 16-color format. Please see the following question for information about this.</p>
<div id="attachment_145" class="wp-caption alignnone" style="width: 232px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_hm_error.png"><img class="size-medium wp-image-145" title="post8_hm_error" src="http://lthzelda.files.wordpress.com/2009/06/post8_hm_error.png?w=222&#038;h=158" alt="The Error You Get When You Try to Import a Picture With Too Many Colors." width="222" height="158" /></a><p class="wp-caption-text">The Error You Get When You Try to Import a Picture With Too Many Colors.</p></div>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Question2"><strong>Question: How Do I Save An Image in 16-Color Format?</strong></a></h3>
<p>Hyrule Magic is very picky about the format of its images. Personally, I think it should have exported and imported <em><strong>files </strong></em>instead of clipboard data, but whatever their rationale, the reality is that you often get a “Bad error” message or screwed up colors when you re-import your graphics. The best way to avoid this problem is at the very beginning: by saving the copied graphics properly as a 4bpp, 16-color bitmap before you perform any editing at all.</p>
<p>We’re going to use the free version of <a href="http://www.humanbalance.net/gale/us/download.html"><strong><span style="color:#0000ff;">Graphics Gale</span></strong></a>, an excellent raster editing program. First, open the program. Then, choose “File-&gt;New”, and enter 128 for the width, 448 for the height, and 4-bit (16 color) for the bit depth. Choose “Ok”.</p>
<p>Now, open a clean Zelda3 ROM in Hyrule Magic, go to the “Link’s graphics” window, and select “Copy”. Then, go back to Graphics Gale. Click on the down-pointing arrow in the palette window, circled below. Then, choose “Load Palette”.</p>
<div id="attachment_143" class="wp-caption alignnone" style="width: 181px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_graphics_gale_palette_menu.png"><img class="size-medium wp-image-143" title="post8_graphics_gale_palette_menu" src="http://lthzelda.files.wordpress.com/2009/06/post8_graphics_gale_palette_menu.png?w=171&#038;h=263" alt="Graphics Gale Hides Its Menus In Non-Standard Context Buttons." width="171" height="263" /></a><p class="wp-caption-text">Graphics Gale Hides Its Menus In Non-Standard Context Buttons.</p></div>
<p>This will bring up a new menu; here, click on “File” and then choose “Import From Clipboard”. You’ll see the palette from Link’s graphics side-by-side with your current palette.</p>
<div id="attachment_135" class="wp-caption alignnone" style="width: 225px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_copying_a_palette.png"><img class="size-medium wp-image-135" title="post8_copying_a_palette" src="http://lthzelda.files.wordpress.com/2009/06/post8_copying_a_palette.png?w=215&#038;h=160" alt="Copying Link's Palette In Graphics Gale." width="215" height="160" /></a><p class="wp-caption-text">Copying Link&#39;s Palette In Graphics Gale.</p></div>
<p>Since we want to use all the new (left-hand-side) colors, click and drag to select all of them, and then click once on the first color of the right-hand palette to paste them in order. (You might also try the &#8220;All&#8221; button, though I&#8217;ve never used it.) Then, click Ok. Now, you can simply paste Link’s graphics into the main drawing window (Ctrl+V) and then save the file. At this point, you should be able to open this file using another program; most good editors won’t change the palette without asking you. If that doesn’t work, you can always edit your sprites in Graphics Gale; it’s a decent stand-alone editor.</p>
<p>I’ve heard that Graphics Gale works on Linux under Wine, at least well enough to perform the steps listed above. If you prefer to use another editor on any OS, <a href="http://hamsterrepublic.com/ohrrpgce/index.php/16-color.html"><span style="color:#0000ff;"><strong>here’s some instructions</strong></span></a> on how to save in 16-color format, in The Gimp, Photoshop, and other popular programs.</p>
<p>Remember, though, that saving in 16-color format won&#8217;t fix the error; you also have to <strong>copy</strong> it  in 16-color format. So you should always copy from Graphics Gale before pasting into Hyrule Magic. This is what makes Hyrule Magic difficult to use at times.</p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Question3"><strong>Question: How Do I Edit Other Graphics? How Do I Use Zcompress and YY-CHR?</strong></a></h3>
<p>Link’s graphics are unique in that they are encoded with 4 bits-per-pixel (a format supported by most major image editors) and they are (I believe) uncompressed. The remaining graphics are much harder to edit. You basically have to follow three steps:</p>
<ol>
<li>Decompress the graphics from your ROM to a .bin file.</li>
<li>Edit the graphics using YY-CHR.</li>
<li>Recompress the graphics in your .bin file and insert them into the ROM.</li>
</ol>
<p>This method is so general that it works for almost any game, so long as you have the right decompression tool. <a href="http://fusoya.eludevisibility.org/lc/index.html"><strong><span style="color:#0000ff;">Lunar Compress</span></strong></a> can handle several popular formats. The only other thing you need to remember is how many bits-per-pixel each graphic is encoded in; please see the Perfect Guide for advice on this, or just look up the palette in Hyrule Magic.</p>
<p>All right, let’s edit Link’s shield graphics. First, open up a command prompt (Start-&gt;Run, type “cmd.exe” and hit Enter. On Vista just click Start, type “cmd” and hit Enter. On Linux… you should know how to do this. <img src='http://s0.wp.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> ) Browse to the directory you saved Zcompress to. Make sure you have also saved a clean Zelda3.smc ROM file there as well. Now, type:</p>
<p><code style="color:black;">zcompress.exe 0 Zelda3.smc Zelda3Gfx.bin</code></p>
<p>…on Linux, you’ll have to do:</p>
<p><code style="color:black;">wine zcompress.exe 0 Zelda3.smc Zelda3Gfx.bin</code></p>
<p>Now, open YY-CHR and select “File-&gt;Open”, then browse to your Zcompress directory. In the “File Name” box, type the following and press Enter:</p>
<p><code style="color:black;"><strong>*.bin</strong></code></p>
<p>This allows you to see .bin files. Now, select your Zelda3Gfx.bin file. The window will load with apparent garbage. You can fix this by clicking on the “Format List” (currently, it shows “4BPP MSX/Genesis) and selecting “4BPP SNES”. Hit PgDown or PgUp to browse through the tileset; you’ll notice that the shapes are familiar but the colors are all wrong.</p>
<div id="attachment_137" class="wp-caption alignnone" style="width: 227px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_editing_mushroomboy.png"><img class="size-medium wp-image-137" title="post8_editing_mushroomboy" src="http://lthzelda.files.wordpress.com/2009/06/post8_editing_mushroomboy.png?w=217&#038;h=158" alt="We've Found Mushroom Boy's Ghost!" width="217" height="158" /></a><p class="wp-caption-text">We&#39;ve Found Mushroom Boy&#39;s Ghost!</p></div>
<p>It’s perfectly fine to edit the sprites using these colors, but you can make them much more accurate with just a little extra effort. The following is taken directly from the Perfect Guide:</p>
<ol>
<li>Decide which sprite you want to edit, and locate that sprite in-game. We’re going to edit Link’s shield, so play through the game in Zsnes until Link’s uncle gives you his shield. Now, save a state (F2) and note the state’s id.</li>
<li>Close Zsnes, and locate the file that was just saved. For example, if you see “State <strong><span style="color:#ff0000;">0</span></strong> saved”, you will be looking for Zelda3.zs<span style="color:#ff0000;"><strong>t</strong></span>; if it’s “State <strong><span style="color:#ff0000;">7</span></strong> changed”, you’ll need Zelda3.zs<span style="color:#ff0000;"><strong>7</strong></span>. Copy this file into the Zcompress directory, to make things easier.</li>
<li>Now, click on “Palette” then “Emulator State Load”. Browse to the Zcompress directory and load your .zs* file. (You might not be able to see it; just type <strong>*.zs*</strong> into the file window, similar to how you located the .bin file.)</li>
<li>Scroll to your sprite in YY-CHR (the shield is roughly 85% of the way down the screen). Now, click on the palette arrows (circled in red, below) to scroll through all possible palettes. You might not find the exact palette; just find one that’s close.</li>
</ol>
<div id="attachment_162" class="wp-caption alignnone" style="width: 286px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_shield_located.png"><img class="size-medium wp-image-162" title="post8_shield_located" src="http://lthzelda.files.wordpress.com/2009/06/post8_shield_located.png?w=276&#038;h=201" alt="Link's Shield, With A Slightly-Distorted Palette." width="276" height="201" /></a><p class="wp-caption-text">Link&#39;s Shield, With A Slightly-Distorted Palette.</p></div>
<p>Now, edit the shield. Make it bigger. As you do this, make sure that you only use the colors already in the palette. Stealing from colors further along is a bad idea, as it makes it much more difficult to edit those other palettes later. Just make something simple, then choose “save”.</p>
<p>After you’ve saved, close YY-CHR; our Zelda3Gfx.bin file now contains our new shield graphics. We just have to re-insert them. Switch back to your command prompt (in the Zcompress directory) and type in:</p>
<p><code style="color:black;">zcompress 1 87200 Zelda3.smc Zelda3Gfx.bin</code></p>
<p>This will re-insert all of your graphics (including the shield) –it will start doing so at 0&#215;87200, which is where a normal Zelda3 ROM expects to see graphics data. Zcompress has the ability to export all graphics as separate files; in this case, you will have to figure out their insertion addresses yourself. But if you always use one big .bin file, the address should always be 87200.</p>
<p>Open your ROM, and play until you get the shield. Don’t your new graphics look nice?</p>
<div id="attachment_138" class="wp-caption alignnone" style="width: 251px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_face_shield.png"><img class="size-medium wp-image-138" title="post8_face_shield" src="http://lthzelda.files.wordpress.com/2009/06/post8_face_shield.png?w=241&#038;h=209" alt="We've Added a Blue Face To Link's Shield, and Enlarged It." width="241" height="209" /></a><p class="wp-caption-text">We&#39;ve Added a Blue Face To Link&#39;s Shield, and Enlarged It.</p></div>
<p>Of course, we can do better than that! Go into the palette editor in Hyrule Magic and scroll down to “Shield 0”. Change the dark blue to white, the light blue to navy, and the white to red. Now, re-arrange your graphics in YY-CHR to look spookier. Ooh~~~ skull shield!</p>
<div id="attachment_164" class="wp-caption alignnone" style="width: 271px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_skull_shield_uncle.png"><img class="size-medium wp-image-164" title="post8_skull_shield_uncle" src="http://lthzelda.files.wordpress.com/2009/06/post8_skull_shield_uncle.png?w=261&#038;h=241" alt="We've Changed the Face Into a Skull! Note That Link's Uncle Uses the Same Shield As His Nephew." width="261" height="241" /></a><p class="wp-caption-text">We&#39;ve Changed the Face Into a Skull! Note That Link&#39;s Uncle Uses the Same Shield As His Nephew.</p></div>
<p>Are we having fun yet? Keep in mind that some graphics are more stubborn than others. I still can’t manage to figure out how to change the treasure chest graphics. Also, some tiles are mirrored, so if you’re editing, say, tombstones, you don’t have to bother looking for the “right half” graphics —they’re simply mirrors of the “left half” graphics.</p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Question4"><strong>Question: How Do I Edit Overworld Tiles? What’s This 16&#215;16 Tile Nonsense?</strong></a></h3>
<p>As mentioned previously, Zelda 3 is hyper-compressed. This makes overworld editing slightly more complex than it should be. Zelda3 enforces a three-tier hierarchy on overworld graphics, the primary purpose of which is to support complex dirt paths, mountain cliffsides, and rivers —all without wasting tiles. It’s pretty natural once you get used to it.</p>
<p>Each world-map “tile” is 32 pixels square. This is just a convenience measure; you cannot, for example, assign properties to any of these tiles. Rather, you assign properties to the four 16&#215;16 tiles that make up one world map tile. 16 pixels square is the “logical” tile size in Zelda. (For now, we ignore &#8220;big&#8221; tiles like the 32&#215;32 rocks Link can pick up.) Each of these, however, is made up four 8&#215;8 tiles which act as a “palette” to construct the larger tile from. If you have, say, a sign which is symmetrical about the Y-axis, it makes sense to simply draw the left-hand-side, and then mirror that tile on the right-hand side. That’s what 8&#215;8 tiles are used for.</p>
<p><strong>Edit: February, 2010</strong></p>
<p>After a bit of discussion with Math on Napkins, I can now explain to you <em>why</em> tiles are stored in a 3-tier hierarchy like this. First: map16 tiles. These make the most sense; you interact with them. Excluding big rocks, each &#8220;actionable&#8221; object is 16 pixels square. The game <strong>engine</strong> (that is to say, Zelda3&#8242;s software) understands these. However, the SNES is hardwired to output 8 pixel tilemaps. So, each tile is stored in <strong>memory</strong> (that is to say, it is stored in &#8220;RAM&#8221;, when you step onto that map) in the SNES. Finally, the Zelda designers realized that there was a lot of redundancy in the overworld. Thus, they decided to store groups of four map16 tiles as map32 tiles in <strong>ROM</strong> (that is to say, on the game cartridge itself, to save space by acting as a rudimentary form of <strong>compression</strong>). Now, map8 and map16 are fairly sensible. But map32 is fairly unique to Zelda; most other games use &#8220;palettes&#8221; of tiles if they run out of room in ROM.</p>
<p>From this, Hyrule Magic has two options for dealing with map32:</p>
<ol>
<li>Force the user (that&#8217;s you) to create/place/manage map32 tiles.</li>
<li>Allow you to place/manage map16 tiles, and then automatically generate map32 tiles when you save the game.</li>
<li>Use its own custom &#8220;compression&#8221; format, and patch Zelda3 to load this instead of map32.</li>
</ol>
<p>Needless to say, #1 is a lot simpler and safer (from the developer&#8217;s point of view) and that&#8217;s why you have to learn to deal with map32.</p>
<p>Just thought I&#8217;d update this while it&#8217;s still fresh in my mind. Happy hacking.</p>
<p><strong>End Edit<br />
</strong></p>
<p>We’re tired of drawing our own graphics, so let’s just re-use existing tiles to make something new. We’ll put the top of a bush onto the bottom of a rock, thus making a sort of “chia pet” tile. This tile is a rock, but it’s also easy to pick up; you don’t need any special gloves. We’ll put this tile outside of Link’s house.</p>
<p>That’s our goal; now let’s do it. Open a clean Zelda3 ROM in Hyrule Magic and go to overworld area 2A. Now click on the “movement” arrows (in red, below) to scroll around until you find Link’s House. Hint: Just move once to the right.</p>
<div id="attachment_142" class="wp-caption alignnone" style="width: 252px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_flute_boys_grotto.png"><img class="size-medium wp-image-142" title="post8_flute_boys_grotto" src="http://lthzelda.files.wordpress.com/2009/06/post8_flute_boys_grotto.png?w=242&#038;h=173" alt="Navigating Is Done With the Four Arrows Circled Here." width="242" height="173" /></a><p class="wp-caption-text">Navigating Is Done With the Four Arrows Circled Here.</p></div>
<p>Remember the room ID (2C) and you can just open it directly next time, or use the “jump to” button. Now, make sure the “Select” button in the top toolbar is depressed, and click/drag to select the two rocks in front of Link’s house. Then, right-click on this square to zoom to the “palette” tile on the right. (You actually don’t have to left-click drag, but I like to have the same tile highlighted on the left and right halves of the screen.) You’ll end up with the following:</p>
<div id="attachment_160" class="wp-caption alignnone" style="width: 250px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_selecting_a_tile.png"><img class="size-medium wp-image-160" title="post8_selecting_a_tile" src="http://lthzelda.files.wordpress.com/2009/06/post8_selecting_a_tile.png?w=240&#038;h=172" alt="Left-Click the Left and Then Right-Click the Left to Load the Right. Easy." width="240" height="172" /></a><p class="wp-caption-text">Left-Click the Left and Then Right-Click the Left to Load the Right. Easy.</p></div>
<p>Double-click on the palette tile (right-hand side) and it will open in the 32&#215;32 block editor. You can see that it is composed of four 16&#215;16 tiles: two rocks, and two “jump down” cliff tiles.</p>
<div id="attachment_128" class="wp-caption alignnone" style="width: 242px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_32x32_editor.png"><img class="size-medium wp-image-128" title="post8_32x32_editor" src="http://lthzelda.files.wordpress.com/2009/06/post8_32x32_editor.png?w=232&#038;h=165" alt="The 32x32 Tile Editor." width="232" height="165" /></a><p class="wp-caption-text">The 32x32 Tile Editor.</p></div>
<p>Right-click on each tile to see its palette tile load in the right-hand side of the 32&#215;32 block editor. Now, scroll down through the various 16&#215;16 palette tiles until you find the dark-colored rock tile. You need to be careful when making new tile graphics; some of them are reserved, some cannot appear on every overworld screen, and some have hard-coded properties. So, we’ll just edit an existing tile that we know is safe: the Lv. 2 rock tile. Double-click on this tile to open it in the 16&#215;16 block editor:</p>
<div id="attachment_127" class="wp-caption alignnone" style="width: 226px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_16x16_editor.png"><img class="size-medium wp-image-127" title="post8_16x16_editor" src="http://lthzelda.files.wordpress.com/2009/06/post8_16x16_editor.png?w=216&#038;h=154" alt="The 16x16 Tile Editor Requires Some Finesse With Palettes." width="216" height="154" /></a><p class="wp-caption-text">The 16x16 Tile Editor Requires Some Finesse With Palettes.</p></div>
<p>On the left is your tile, composed of four 8&#215;8 tiles. On the right are your “palette” 8&#215;8 tiles. Unfortunately, Hyrule Magic cannot know which palette your map will be using, so the colors are a bit screwy. Try typing various numbers into the “palette” dialogue until the graphics normalize. Palette number “5” or “6” is a good choice. If you double-clicked on an 8&#215;8 tile, you could edit it further, but we want to just build our new tile from the existing “bush” and “rock” graphics.</p>
<p>However, there are several different bush/rock graphics, so which one should we copy? Close the 16&#215;16 tile editor and right-click on the original (Lv. 1) rock. Then, double-click on its palette entry. Finally, right-click on each of the bottom two tiles. They are both palette 5, block 434, and one of them has the “X flip” attribute set. Cancel, and do the same for a “bush” tile from the world map. You’ll see that the top two tiles are both palette 6, block 384, and one of them has the X-flip attribute set. Now that we know this information, we can easily construct our new tile:</p>
<ol>
<li>Re-open the “black rock” tile in the 16&#215;16 block editor.</li>
<li>Enter “5” for the palette.</li>
<li>Type “434” into the “Block” window. Left-click on the lower-left tile to place this.</li>
<li>Click the “X flip” check box. Left-click on the lower-right tile to place this.</li>
<li>Uncheck “X flip” and enter “384” for the block and “6” for the palette. Left-click on the upper-left tile to place it.</li>
<li>Check the “X flip” box and left-click on the upper-right tile to place it.</li>
<li>Change the “Block type” to “39”, the same type as bushes, so that you can pick it up and slash it with your sword.</li>
</ol>
<p>You should now have a proper bush-rock-combination tile. Click “Ok” and then left-click on your new tile in the palette window, then left-click on each of the two rocks to change them to chia tiles.</p>
<div id="attachment_133" class="wp-caption alignnone" style="width: 276px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_changing_16x16_tiles.png"><img class="size-medium wp-image-133" title="post8_changing_16x16_tiles" src="http://lthzelda.files.wordpress.com/2009/06/post8_changing_16x16_tiles.png?w=266&#038;h=199" alt="We've Successfully Merged Rocks and Bushes." width="266" height="199" /></a><p class="wp-caption-text">We&#39;ve Successfully Merged Rocks and Bushes.</p></div>
<p>Then, click “Ok”. The bushes in front of Link’s house should now appear as rock-bushes. It is possible, however, that your new tile is all black. You’ll first notice this in the 16&#215;16 block editor:</p>
<div id="attachment_155" class="wp-caption alignnone" style="width: 278px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_palette_screwiness.png"><img class="size-medium wp-image-155" title="post8_palette_screwiness" src="http://lthzelda.files.wordpress.com/2009/06/post8_palette_screwiness.png?w=268&#038;h=190" alt="Sometimes The 16x16 Palettes Won't Refresh." width="268" height="190" /></a><p class="wp-caption-text">Sometimes The 16x16 Palettes Won&#39;t Refresh.</p></div>
<p>If this is the case, simply select “Ok”, and then look for the “Palette” box in the overworld map window. Currently, the entry is “0”. Change it to “5”, then change it <strong><em>back</em></strong> to “0” to fix the problem.</p>
<p>You will probably also get a warning message when you save the game:</p>
<div id="attachment_159" class="wp-caption alignnone" style="width: 263px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_save_prompt.png"><img class="size-medium wp-image-159" title="post8_save_prompt" src="http://lthzelda.files.wordpress.com/2009/06/post8_save_prompt.png?w=253&#038;h=181" alt="Editing the World Map Can Lead To Difficulty Saving." width="253" height="181" /></a><p class="wp-caption-text">Editing the World Map Can Lead To Difficulty Saving.</p></div>
<p>This is because several areas share some common tiles (like the dark black rock you edited). Personally, I’m wary of selecting “Yes”, since I don&#8217;t trust the editor to &#8220;fix&#8221; this problem. Clicking “No” has one obvious side-effect, though: it replaces all black rocks with your rock-bushes. I find this acceptable; we’re only testing out the area near Link’s house anyway.</p>
<p>Now, simply play the game, and enjoy your new bush-rocks.</p>
<div id="attachment_158" class="wp-caption alignnone" style="width: 251px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_rocks_rock.png"><img class="size-medium wp-image-158" title="post8_rocks_rock" src="http://lthzelda.files.wordpress.com/2009/06/post8_rocks_rock.png?w=241&#038;h=222" alt="The Bush-Rocks Work... Mostly." width="241" height="222" /></a><p class="wp-caption-text">The Bush-Rocks Work... Mostly.</p></div>
<p>There are a few minor issues, such as the fact that these new tiles occasionally drop bombs, or the incorrect “full rock” graphic that appears when you pick it up, but the general effect is nice.</p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Lunch"><strong>Lunch~</strong></a></h3>
<p>It’s lunch time and we’re not even halfway done. Grab a sandwich (I recommend a Reuben) and get ready for more barrels of fun when we return.</p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Question5"><strong>Question: How Do I Change Flute Locations?</strong></a></h3>
<p>Changing the 8 flute locations (we ignore the special 9th location) is quite easy to do, but it requires two rather unrelated steps:</p>
<ol>
<li>Change the location of the flashing number on the world map.</li>
<li>Change the location the bird drops you off at on the proper Overworld screen.</li>
</ol>
<p>Neither step is difficult. First, open Hyrule Magic and click on “World Maps” and then “Normal World”. Change the selected marker from “Hyrule Castle” to “Flute Locations” —the very last item in the drop-down list.</p>
<div id="attachment_168" class="wp-caption alignnone" style="width: 245px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_viewing_flute_locations.png"><img class="size-medium wp-image-168" title="post8_viewing_flute_locations" src="http://lthzelda.files.wordpress.com/2009/06/post8_viewing_flute_locations.png?w=235&#038;h=174" alt="Eight of the Nine Flute Locations, As Seen On The In-Game Map." width="235" height="174" /></a><p class="wp-caption-text">Eight of the Nine Flute Locations, As Seen On The In-Game Map.</p></div>
<p>Personally, I’ve always found location 8 to be a bit lame. Let’s move it to a more useful place: the Great Fairy’s island. To do this, click on the “Move” button in the top toolbar, then simply drag the pink 8 to the center of the lake.</p>
<div id="attachment_151" class="wp-caption alignnone" style="width: 245px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_moving_the_maps_flute_point.png"><img class="size-medium wp-image-151" title="post8_moving_the_maps_flute_point" src="http://lthzelda.files.wordpress.com/2009/06/post8_moving_the_maps_flute_point.png?w=235&#038;h=175" alt="Drag the Flute Location to the Island." width="235" height="175" /></a><p class="wp-caption-text">Drag the Flute Location to the Island.</p></div>
<p>Save, and close the world map editor. If you opened the saved game now, you’d see the flashing number 8 in its new location, but the bird would still bring you to the old location. To fix this, open “Overworld” area 3F. Click on the “Transport” button to show the whirlpools and bird locations, and then right-click on “Fly-8” and choose “Remove”.</p>
<div id="attachment_157" class="wp-caption alignnone" style="width: 247px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_removing_the_old_flute_point.png"><img class="size-medium wp-image-157" title="post8_removing_the_old_flute_point" src="http://lthzelda.files.wordpress.com/2009/06/post8_removing_the_old_flute_point.png?w=237&#038;h=165" alt="Hyrule Magic Will Complain If You Don't Remove the Old Flute Point First." width="237" height="165" /></a><p class="wp-caption-text">Hyrule Magic Will Complain If You Don&#39;t Remove the Old Flute Point First.</p></div>
<p>Now, move to area 35 and right-click on the island, then choose “Insert bird location”. Congratulations! You’ve moved the drop-off point.</p>
<div id="attachment_183" class="wp-caption alignnone" style="width: 245px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_inserting_a_new_flute_location.png"><img class="size-medium wp-image-183" title="post8_inserting_a_new_flute_location" src="http://lthzelda.files.wordpress.com/2009/06/post8_inserting_a_new_flute_location.png?w=235&#038;h=164" alt="Adding a New Flute Location is Easy Once You Know Where to Look For It." width="235" height="164" /></a><p class="wp-caption-text">Adding a New Flute Location is Easy Once You Know Where to Look For It.</p></div>
<p>Save your map. Before testing it out, you should probably short-circuit a few of the doors in the castle, to make evacuating Zelda easier. Also, put the Flute in the treasure chest in Link’s house. This way, you can start a new game, rescue Zelda, and activate the bird in Kakariko Village without wasting too much time. The end result is exactly what we expected, except…</p>
<div id="attachment_167" class="wp-caption alignnone" style="width: 217px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_using_the_new_flute.png"><img class="size-medium wp-image-167" title="post8_using_the_new_flute" src="http://lthzelda.files.wordpress.com/2009/06/post8_using_the_new_flute.png?w=207&#038;h=191" alt="The Map Is Properly Up-To-Date." width="207" height="191" /></a><p class="wp-caption-text">The Map Is Properly Up-To-Date.</p></div>
<div id="attachment_184" class="wp-caption alignnone" style="width: 223px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_warping_in_with_the_flute.png"><img class="size-medium wp-image-184" title="post8_warping_in_with_the_flute" src="http://lthzelda.files.wordpress.com/2009/06/post8_warping_in_with_the_flute.png?w=213&#038;h=196" alt="Link Also Zooms In To the New Location Correctly." width="213" height="196" /></a><p class="wp-caption-text">Link Also Zooms In To the New Location Correctly.</p></div>
<p>Our rock-bush tile is still in effect from the pre-lunch hack. This has some unintended consequences:</p>
<div id="attachment_166" class="wp-caption alignnone" style="width: 225px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_unintended_flute_consequences.png"><img class="size-medium wp-image-166" title="post8_unintended_flute_consequences" src="http://lthzelda.files.wordpress.com/2009/06/post8_unintended_flute_consequences.png?w=215&#038;h=199" alt="Did Anyone Else Notice That Those Ice Men Were Super-Damaging?" width="215" height="199" /></a><p class="wp-caption-text">Did Anyone Else Notice That Those Ice Men Were Super-Damaging?</p></div>
<p>But that’s nothing you can’t handle, right? <img src='http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Question6"><strong>Question: How Do I Edit The Game’s 3-D Graphics? How Complex Can These Graphics Be?</strong></a></h3>
<p>The answer to the second question is: not very. The combination of points and faces is limited to 104 units in total, but I’m not sure how these are tallied. (My personal guess? 3 units for each point you place, and one unit for each point in a face.) Also, the triforce segments and crystal shards share the same total point set. For now, you’ll just have to experiment with the editor to see what its limits are.</p>
<p>To answer the first question, open a clean Zelda3 ROM in Hyrule Magic and click the “3D Objects” tab. Then click once on the black, gridded area to focus it. Now, you can rotate the scene (arrow keys) and zoom (num pad plus/minus). The current view, of the crystals, is somewhat difficult to grasp, so hit the right arrow in the upper-left of the screen to switch to editing the triforce shards.</p>
<div id="attachment_125" class="wp-caption alignnone" style="width: 245px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_3d_movement.png"><img class="size-medium wp-image-125" title="post8_3d_movement" src="http://lthzelda.files.wordpress.com/2009/06/post8_3d_movement.png?w=235&#038;h=181" alt="Hyrule Magic's 3D Shape Editor is Impressive, But Slightly Tricky to Use." width="235" height="181" /></a><p class="wp-caption-text">Hyrule Magic&#39;s 3D Shape Editor is Impressive, But Slightly Tricky to Use.</p></div>
<p>You should then click on each point on the top surface of the triforce to see its location in 3D-space, which will appear in the upper-left corner of the screen.</p>
<div id="attachment_126" class="wp-caption alignnone" style="width: 243px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_3d_point.png"><img class="size-medium wp-image-126" title="post8_3d_point" src="http://lthzelda.files.wordpress.com/2009/06/post8_3d_point.png?w=233&#038;h=189" alt="Click On A Point To Show Its Position In 3D Space." width="233" height="189" /></a><p class="wp-caption-text">Click On A Point To Show Its Position In 3D Space.</p></div>
<p>Here, we can see that this point is located at X:A8, Y:58, Z:76. Click on the remaining points and jot them down. These coordinates, of course, are hex values.</p>
<table style="font-family:courier;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td><strong><em>Face</em></strong></td>
<td><strong><em>X</em></strong></td>
<td><strong><em>Y</em></strong></td>
<td><strong><em>Z</em></strong></td>
</tr>
<tr>
<td rowspan="3">Top Face</td>
<td>A8</td>
<td>58</td>
<td>76</td>
</tr>
<tr>
<td>58</td>
<td>58</td>
<td>76</td>
</tr>
<tr>
<td>80</td>
<td>A8</td>
<td>76</td>
</tr>
<tr>
<td rowspan="3">Bottom Face</td>
<td>A8</td>
<td>58</td>
<td>8A</td>
</tr>
<tr>
<td>58</td>
<td>58</td>
<td>8A</td>
</tr>
<tr>
<td>80</td>
<td>8A</td>
<td>8A</td>
</tr>
</tbody>
</table>
<p>The triangle is 0&#215;14 points thick, with the bottom face flat on 0x8A and the top face flat on 0&#215;76. The remaining Cartesian co-ordinates are distributed as an equilateral triangle:</p>
<div id="attachment_165" class="wp-caption alignnone" style="width: 224px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_triangle_diagram.png"><img class="size-medium wp-image-165" title="post8_triangle_diagram" src="http://lthzelda.files.wordpress.com/2009/06/post8_triangle_diagram.png?w=214&#038;h=166" alt="Our Equilateral Triforce Piece." width="214" height="166" /></a><p class="wp-caption-text">Our Equilateral Triforce Piece.</p></div>
<p>We would like to replace the triangle with a nice hexagonal shape. However, if you try to add a point, you’ll notice that we don’t have any more points to work with. So, click the left arrow (at the top-left of the window) to switch back to the crystals, and then click on any one of the points. Hit “Backspace” to delete this point —the cursor will then automatically jump to the next point. Continue hitting “backspace” until all points have been deleted. Then, hit the “right” arrow to go to the triforce triangle, and delete all points here too.</p>
<p>Now, draw a rough sketch of your hexagon; it should be roughly the same size as the triangle. Drawing a sketch is important, as it allows you to identify vertices easily. You should end up with something like this:</p>
<div id="attachment_144" class="wp-caption alignnone" style="width: 247px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_hexagon_diagram.png"><img class="size-medium wp-image-144" title="post8_hexagon_diagram" src="http://lthzelda.files.wordpress.com/2009/06/post8_hexagon_diagram.png?w=237&#038;h=185" alt="Our Hexa-Force is At Least Twice As Powerful As the Triforce!" width="237" height="185" /></a><p class="wp-caption-text">Our Hexa-Force is At Least Twice As Powerful As the Triforce!</p></div>
<p>Now we have our six points in a single z-plane:</p>
<p><code style="color:black;">(6C,58), (94,58), (A8,80), (94,A8), (6C,A8), (58,80)</code></p>
<p>You’ll notice that I wrote these out in a counter-clockwise order. The reason will be important later: Hyrule Magic creates an “outward facing” shape when points are connected counter-clockwise.</p>
<p>Now, we need to enter these points. To enter the first point, (6C,58), do the following:</p>
<ol>
<li>Click the “Add Points” button, and click once on the black area. This will pull up a blue line and two green lines, indicating the temporary placement of your point.</li>
<li>Click on one of the green lines to place your point. Place it anywhere; we’ll move it manually to make sure it ends up at the exact position we choose.</li>
<li>Click the “Move” button, then left-click once on your new point. Now, press the A or Z key until the point’s “Z coordinate” is at 76. Then, use the numeric keypad (this part sucks on a laptop) to shift the point’s X/Y coordinates to 6C and 58, respectively.</li>
</ol>
<div id="attachment_150" class="wp-caption alignnone" style="width: 243px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_moving_the_first_point.png"><img class="size-medium wp-image-150" title="post8_moving_the_first_point" src="http://lthzelda.files.wordpress.com/2009/06/post8_moving_the_first_point.png?w=233&#038;h=201" alt="Our First Point, Positioned Correctly In 3D Space." width="233" height="201" /></a><p class="wp-caption-text">Our First Point, Positioned Correctly In 3D Space.</p></div>
<p>Continue to add all the points; the order you <strong>add </strong>them in is not important (only the order you <strong>connect </strong>them in). The Z-component will always be 76, since we’re only building the top face for now. Then, after all points have been added, rotate the view to the origin (the easy way: save, close, and re-open your ROM in Hyrule Magic), click the “Add Faces” button and click on each point in order. It doesn’t matter where you start, so long as you go in a <strong>counter</strong>-clockwise direction, and end at your starting point. As you click on each point, a blue line will trace the current shape you’re creating. You should have something like this when you’re done:</p>
<div id="attachment_141" class="wp-caption alignnone" style="width: 236px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_first_face.png"><img class="size-medium wp-image-141" title="post8_first_face" src="http://lthzelda.files.wordpress.com/2009/06/post8_first_face.png?w=226&#038;h=195" alt="Our First Hexagon Surface. 1-Dimensional." width="226" height="195" /></a><p class="wp-caption-text">Our First Hexagon Surface. 1-Dimensional.</p></div>
<p>Save your file and close the editor. Start up the ROM, and you’ll see some blinking hexagons:</p>
<div id="attachment_163" class="wp-caption alignnone" style="width: 241px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_single_hexagon.png"><img class="size-medium wp-image-163" title="post8_single_hexagon" src="http://lthzelda.files.wordpress.com/2009/06/post8_single_hexagon.png?w=231&#038;h=200" alt="Our 1-D Hexagons Often Vanish, But Prove the Concept." width="231" height="200" /></a><p class="wp-caption-text">Our 1-D Hexagons Often Vanish, But Prove the Concept.</p></div>
<p>This is fine; the back face of the hexagons is invisible; we’ll fix that later. If, instead of loading, your game shows some glitchy graphics and then freezes up, you probably edited the crystal’s graphics instead of the triforce’s graphics (d’oh!). Just delete all points, hit the “right” arrow, and start again.</p>
<p>Let’s add the second set of points. Load your ROM in Hyrule Magic and go to the 3D Objects editor, pressing “right” to go to the triforce graphics. You should see the hexagon facing you directly; hold “Down” to rotate the screen until you are seeing the back of the hexagon. Now, add six new points to the object. They have the same X and Y coordinates as the previous points, but their Z-coordinates are all the same: 8A.</p>
<p>After you’ve added these points, hit “Up” two or three times so that you can tell these points apart from the first set. Then, connect all six in a counter-clockwise direction using the “Add Face” button. You now should have two hexagons facing away from each other:</p>
<div id="attachment_129" class="wp-caption alignnone" style="width: 242px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_added_2_faces.png"><img class="size-medium wp-image-129" title="post8_added_2_faces" src="http://lthzelda.files.wordpress.com/2009/06/post8_added_2_faces.png?w=232&#038;h=171" alt="Our 2 Faces of the Coin Have Been Added. One Should Always Be Invisible." width="232" height="171" /></a><p class="wp-caption-text">Our 2 Faces of the Coin Have Been Added. One Should Always Be Invisible.</p></div>
<p>There’s a small chance that you’ll corrupt your first face by adding the points for the second. In this case, the “Delete Face” button might not even work! You’ll have to delete one of the <em><strong>points </strong></em>contained in the face. (In my case, there was a weird triangular shape; I just deleted and re-added one of the points of that triangle.) In general, you’ll want to add all points before you connect any faces.</p>
<p>Either way, you only have one more task before we’re done: just add each of the six rectangles that connect the top and bottom two hexagons. Rotate the window as you go, and make sure you connect all points in a counter-clockwise fashion. When you’re done, you’ll have a nice, coin-ish object.</p>
<div id="attachment_139" class="wp-caption alignnone" style="width: 310px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_final_coin.png"><img class="size-medium wp-image-139" title="post8_final_coin" src="http://lthzelda.files.wordpress.com/2009/06/post8_final_coin.png?w=300&#038;h=239" alt="My Favorite Picture From This Entire Post: Your Complete Coin." width="300" height="239" /></a><p class="wp-caption-text">My Favorite Picture From This Entire Post: Your Complete Coin.</p></div>
<p>Save and exit, then load your game. My only regret is that I didn’t actually do the math properly, so our coin is a bit “longer” than it should be.</p>
<div id="attachment_140" class="wp-caption alignnone" style="width: 220px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_final_coin_in_emu.png"><img class="size-medium wp-image-140" title="post8_final_coin_in_emu" src="http://lthzelda.files.wordpress.com/2009/06/post8_final_coin_in_emu.png?w=210&#038;h=182" alt="Our Coins Rotate Into Position. Hooray, 3-D Editor!" width="210" height="182" /></a><p class="wp-caption-text">Our Coins Rotate Into Position. Hooray, 3-D Editor!</p></div>
<p>Does anyone else find it interesting that <a href="http://byuu.org/bsnes/"><strong><span style="color:#0000ff;">bsnes </span></strong></a>and <a href="http://www.zsnes.com/"><strong><span style="color:#0000ff;">zsnes</span></strong></a> display the opening zoom-in differently? Also, although it should be painfully obvious by now, you can change the palette used for the triforce just like anything else in the game:</p>
<div id="attachment_156" class="wp-caption alignnone" style="width: 217px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_rainbow_triforce.png"><img class="size-medium wp-image-156" title="post8_rainbow_triforce" src="http://lthzelda.files.wordpress.com/2009/06/post8_rainbow_triforce.png?w=207&#038;h=178" alt="Go Rainbow Laser Triforce!" width="207" height="178" /></a><p class="wp-caption-text">Go Rainbow Laser Triforce!</p></div>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Question7"><strong>Question: How Do I Change The Music For An Area?</strong></a></h3>
<p>I’m pitching a changeup with this one. Sorry, but I need an easy section for once. Changing the music for an area is just a matter of tracking down the right dialog box. The one you want is in the “Overworld” editor, called “Properties”.</p>
<div id="attachment_153" class="wp-caption alignnone" style="width: 209px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_overworld_properties.png"><img class="size-medium wp-image-153" title="post8_overworld_properties" src="http://lthzelda.files.wordpress.com/2009/06/post8_overworld_properties.png?w=199&#038;h=155" alt="Here's The Overworld Properties Dialogue." width="199" height="155" /></a><p class="wp-caption-text">Here&#39;s The Overworld Properties Dialogue.</p></div>
<p>Since I’m punting on this one, I’ll at least explain this box properly. Besides a section that lets you change the sign text (by ID), all eight options relate to music and sound. The four categories relate to the four stages of the game:</p>
<ol>
<li>“Beginning” — From the game’s beginning until you get Zelda to the sanctuary.</li>
<li>“After rescuing Zelda” — From the sanctuary until you retrieve the Master Sword (regardless of if you’ve visited the Dark World yet).</li>
<li>“After getting the Master Sword” — From the time you get the Master Sword (Lv. 2) until the time you get teleported to the Dark World from Hyrule Castle.</li>
<li>“After beating Agahnim” — From the time you defeat Agahnim and are teleported until you beat the game.</li>
</ol>
<p>The “music” option is simple: What music plays for this section of the screen during the designated time period? Try changing all “music” to “Forest” to see what happens. You should be able to guess. The “ambient sound” setting loops a background noise constantly when on. Try changing the sound to “Light Rain” for all four time slots. Now, when you enter this particular screen, you will always hear rain <em><strong>and </strong></em>the music from the Lost Woods. In the Dark World, there is generally only one time slice available. Try mixing and matching various sounds and music tracks to get the effect you want; actually changing the music itself will be covered in an “Advanced” tutorial later.</p>
<p>Thanks for the easy question~</p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Question8"><strong>Question: How Do I Make An Enemy Drop a Key? How Do I Choose Which Enemy Drops the Key?</strong></a></h3>
<p>This is a reasonable question to ask; although long-time Zelda players know that certain enemies drop keys in certain rooms, the Perfect Guide says to just “put the key at 00,3C,2” and pretty much leaves it at that. The actual method is slightly more involved:</p>
<ol>
<li>Open a clean ROM in Hyrule Magic. Go to Entrance 04, the main entrance to Hyrule Castle.</li>
<li>Click on the “Sprite” checkbox, and then right-click anywhere on the map and choose “Insert An Enemy”. Scroll through the list until you find the “Key” entry and choose Ok. Then, click and drag that sprite to location X:00, Y:3C. Now, press the hyphen (minus) key to make it jump to “BG2”. Finally, press the period key several times until its property (P) value is 18.</li>
<li>Now, press the left arrow key several times, to move to the <em><strong>first </strong></em>sprite in the room. Hit the right arrow key to scroll through the sprites one-by-one, and <em><strong>pay attention</strong></em> to the order of the sprites. Your key sprite will appear directly <em><strong>after </strong></em>the enemy that drops it.</li>
<li>So, click on your key sprite and press “V” or “B” to move it forward or backwards in the order until it is directly after the enemy you want to drop the key. You might have to use the left/right arrow keys to check, in case you lose track of the current order.</li>
</ol>
<p>Make sense? Here’s a picture of my screen after I’ve edited the key sprite and positioned it properly. Note the properties tab (circled) and the order of the sprites (drawn as a red connected path). According to this screenshot, you can determine that the key will appear after killing the “Green Soldier” enemy.</p>
<div id="attachment_161" class="wp-caption alignnone" style="width: 246px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_setting_a_key.png"><img class="size-medium wp-image-161" title="post8_setting_a_key" src="http://lthzelda.files.wordpress.com/2009/06/post8_setting_a_key.png?w=236&#038;h=216" alt="Annotated Screenshot Showing How Enemy Order Determines Who Drops the Key. Also Note the Object's Properties." width="236" height="216" /></a><p class="wp-caption-text">Annotated Screenshot Showing How Enemy Order Determines Who Drops the Key. Also Note the Object&#39;s Properties.</p></div>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Question9"><strong>Question: How Do I Add a Nifty Logo To The Title Screen?</strong></a></h3>
<p>This question&#8217;s more a matter of patience than anything. The “Menu screens” tab in Hyrule Magic lists a series of single screens that you&#8217;ll recognize from the game. For now, open the last menu: “Destination List”. The player sees this menu whenever he starts the game any time <em><strong>after </strong></em>rescuing Zelda. There are several problems with the initial view, however.</p>
<div id="attachment_191" class="wp-caption alignnone" style="width: 228px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_choose_location_menu.png"><img class="size-medium wp-image-191" title="post8_choose_location_menu" src="http://lthzelda.files.wordpress.com/2009/06/post8_choose_location_menu.png?w=218&#038;h=146" alt="The Destination Picker Window." width="218" height="146" /></a><p class="wp-caption-text">The Destination Picker Window.</p></div>
<p>For one, the menu box and the fairy used to select your location are not visible, making it very difficult to decide where to place the logo. This occurs because such graphics are sprites, whereas the background is just a static image. We&#8217;ll get around this problem by using placeholders.</p>
<p>The next issue is that we can&#8217;t even see the palette tiles that make up the text! Click on the BG3 radio button; ah, there they are.</p>
<p>An altogether different sort of problem is one you should be used to by now: the palette&#8217;s miscolored. Keep trying numbers until you get something that looks good; I used 6.</p>
<p>However, we&#8217;ve now reached the main issue: editing the last five menu items usually doesn&#8217;t work. This includes the &#8220;Destination List&#8221;, of course. I&#8217;ve tried adding tiles on BG&#8217;s 1, 2, and 3, with or without the “In Front” property specified, all to no avail. There&#8217;s a chance that changing the palette would fix the problem, but I&#8217;d had enough by then. Close the “Destination list”; we&#8217;ll have to edit something else.</p>
<p>Double-click to open the “Title Screen”, which is much easier to edit. The only thing I haven&#8217;t been able to add yet is BG3 sprites. (Actually, I know they&#8217;re in there, since the Master Sword is obstructed by their shadows. But I can&#8217;t get them to show up.) This isn&#8217;t such a big restriction, since we&#8217;ll be drawing our own graphics anyway.</p>
<p>Menu screens are somewhat like dungeon screens, which makes it surprising that the same editor logic isn&#8217;t used. Instead, we&#8217;ve got a bunch of random keys which help us accomplish our tasks. Make sure the “Move” button at the top of the window is pressed down, and click once on the blue sky above the word “Zelda”. Notice how several tiles were selected? This is a common theme in menu screens: a “block” of editable tiles. You can drag a block of tiles with the mouse, and increase or decrease its size with the period and comma keys. Pressing m changes if “size” refers to width or height. If you want all tiles in a block to have the same value, press the hyphen (subtraction) key to switch between normal mode and “fill” mode. Note that dragging a block to the edges of the screen can sometimes cause it to auto-fill the entire width, just like in the Dungeon Editor.</p>
<p>Before we place our logo (which will be 3&#215;2 tiles), we first have to place a dummy sprite and make sure it shows up in the right place. We&#8217;ll use two blocks of 3 tiles. Switch to “Move” mode, and switch to “BG1”. (<em><strong>Note</strong></em>: Click the <strong>radio button</strong> BG1, not the <strong>check box</strong> BG1. The check box just toggles the visibility, to make editing easier.) Now, right-click somewhere below the bottom of Hyrule Lake. A new block should appear. Hit the period key twice to make it expand.</p>
<div id="attachment_130" class="wp-caption alignnone" style="width: 264px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_adding_a_new_block.png"><img class="size-medium wp-image-130" title="post8_adding_a_new_block" src="http://lthzelda.files.wordpress.com/2009/06/post8_adding_a_new_block.png?w=254&#038;h=175" alt="Right-Click With &quot;Move&quot; Selected=" width="254" height="175" /></a><p class="wp-caption-text">Right-Click With &quot;Move&quot; Selected To Add A New Block. Then Resize It.</p></div>
<p>Now, switch to “draw” mode, and pick any colorful tile. Click on it in the palette on the right, then left-click and drag over your new block to fill all three tiles in that block with your new tile.</p>
<div id="attachment_134" class="wp-caption alignnone" style="width: 260px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_coloring_block_1.png"><img class="size-medium wp-image-134" title="post8_coloring_block_1" src="http://lthzelda.files.wordpress.com/2009/06/post8_coloring_block_1.png?w=250&#038;h=172" alt="Left-Click and Drag to Color the New Block. Hit Detection Is Sometimes Dodgy Here..." width="250" height="172" /></a><p class="wp-caption-text">Left-Click and Drag to Color the New Block. Hit Detection Is Sometimes Dodgy Here...</p></div>
<p>Switch back to “Move” mode, and right-click one tile below the block you just entered. Press period twice to expand it to 3 tiles. Switch to draw mode and color it with another random tile from the palette. Now, switch back to draw mode and drag both of your new blocks until they&#8217;re in a sensible position.</p>
<div id="attachment_146" class="wp-caption alignnone" style="width: 243px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_initial_logo_placement_in_editor.png"><img class="size-medium wp-image-146" title="post8_initial_logo_placement_in_editor" src="http://lthzelda.files.wordpress.com/2009/06/post8_initial_logo_placement_in_editor.png?w=233&#038;h=160" alt="Our First Tentative Placement of Logo Stand-In Graphics." width="233" height="160" /></a><p class="wp-caption-text">Our First Tentative Placement of Logo Stand-In Graphics.</p></div>
<p>Now, save your game, and load it in Zsnes. Your faux-logo should be in the right spot; if not, go back to Hyrule Magic and move it until it shows up properly. In particular, if you can&#8217;t see it at all, something is overlapping it. Or, you&#8217;ve chosen a bad palette. Try re-drawing your title screen graphics after first changing the “palette” in the Menu editor. I used palette 4 pretty effectively.</p>
<div id="attachment_149" class="wp-caption alignnone" style="width: 238px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_logo_placed_in_zsnes.png"><img class="size-medium wp-image-149" title="post8_logo_placed_in_zsnes" src="http://lthzelda.files.wordpress.com/2009/06/post8_logo_placed_in_zsnes.png?w=228&#038;h=210" alt="After Some Fiddling and Re-Coloring, Here's Our Logo Placeholder Graphics in Zsnes." width="228" height="210" /></a><p class="wp-caption-text">After Some Fiddling and Re-Coloring, Here&#39;s Our Logo Placeholder Graphics in Zsnes.</p></div>
<p>Now that we&#8217;ve got the logo in place, we just have to edit its graphics. You should know how to save graphics in 16-color format (see question 2), and you should know how to edit Link&#8217;s graphics by exporting them (question 1) or with YY-CHR (question 3). Either of these will work. First, go back to your menu editor, and select the proper palette. Then, double-click on one of the tiles in the <em><strong>right-hand</strong></em> box that you previously added. A new window should pop up.</p>
<div id="attachment_136" class="wp-caption alignnone" style="width: 230px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_copy_menu_titles.png"><img class="size-medium wp-image-136" title="post8_copy_menu_titles" src="http://lthzelda.files.wordpress.com/2009/06/post8_copy_menu_titles.png?w=220&#038;h=148" alt="The Import/Export Window for Menu Tiles." width="220" height="148" /></a><p class="wp-caption-text">The Import/Export Window for Menu Tiles.</p></div>
<p>You should know what to do here: copy and paste these graphics into Graphics Gale and save it in 16-color format. Then, open Paint.NET and edit some of the tiles (using only palette colors) to create a desirable logo. Make sure you don&#8217;t edit any of the tiles that appear in the title screen. Some of the all-black tiles are probably safe to edit, but if you don&#8217;t mind messing up existing graphics in other menus, just edit tiles that you know for sure don&#8217;t appear in the title screen. Finally, copy/paste your edited spritesheet from Graphics Gale back into Hyrule Magic, and then switch to “Draw” mode and click on each of your six new tiles to insert them where your placeholder graphics used to be. Congratulations, you&#8217;ve made a new logo!</p>
<div id="attachment_131" class="wp-caption alignnone" style="width: 242px"><a href="http://lthzelda.files.wordpress.com/2009/06/post8_add_logo.png"><img class="size-medium wp-image-131" title="post8_add_logo" src="http://lthzelda.files.wordpress.com/2009/06/post8_add_logo.png?w=232&#038;h=202" alt="Our Completed Logo. Note: The Graphical Glitches Are Unrelated To The Logo; I Just Messed Up The Import." width="232" height="202" /></a><p class="wp-caption-text">Our Completed Logo. Note: The Graphical Glitches Are Unrelated To The Logo; I Just Messed Up The Import.</p></div>
<p>Of course, if you&#8217;re willing to track down and manage the palette colors yourself, you can probably make a much nicer logo. We won&#8217;t cover changing the palette on image imports, as the Perfect Guide has a few nice examples on that.</p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="QuestionB"><strong>Bonus: How Do I Actually Manage a Large Project?</strong></a></h3>
<p>Instead of giving you homework, I’ll give you my own personal bit of advice on how to manage a real project with Hyrule Magic. Learning the program is fairly easy, and coming up with creative dungeon ideas is either simple or impossible —it’s more of an art than a science. So the only real challenge is the organizational aspect. What if you want to steal a palette color from Link’s shield to use in his hat? Even if you set aside the same color in all three “shield” palettes, you’ll still have to jot this information down somewhere. What if you want to play around with the enemy palettes available in each dungeon, to make, say, crystal switches available everywhere? Hyrule Magic’s occasional corrupting of your ROM doesn’t make this any easier.</p>
<p>The key idea here is that you should somehow <em><strong>extract </strong></em>a “source” version of Zelda3, and then re-insert it into the ROM when you want to open it up in Hyrule Magic. The ZCompress tutorial I wrote is a good example of this. Some programs go even further, re-writing the game’s ASM to force you to change the ROM. Lunar Magic sometimes does this, relocating pointers and the like. However, I see no need to toss out Hyrule Magic for, say, Open Zelda. Can’t we find a way to perform our extract-edit-insert cycle without mangling the ROM so badly that Hyrule Magic can’t open it? That way, we can try out new ideas (and do dungeon design, etc.) in Hyrule Magic, and take advantage of all the work done by its developers on understanding the Zelda3 format. On a related note, can’t we add some capability for backup?</p>
<p>I forsee two possible solutions:</p>
<ul>
<li>Use a makefile to “build” your ROM from a series of text and binary files. As you decide to edit a new part of Zelda3, you can create a text file representing that particular aspect in a useful way. Then, you can define logic for importing it into the ROM. You’ll also need some way to “extract” dungeon rooms from Zelda3, and save them as .bin files (just the HEX values, really). That way, you can back up your work as you go. If Hyrule Magic corrupts your data, just delete the ROM and run a “make” command to generate a new one. This approach also allows you to throw your project into a repository, making it easier for others to help out with.</li>
<li>Use Microsoft Excel and VBA macros. Although there are several great programming languages out there, Excel is one of the few good 2-dimensional ones. Consider: you write a macro to import a PNG of Link’s poses and display each one in a separate cell. Then, you generate cells representing each palette color. Another sheet can contain information on Zelda3’s palettes and how they relate. Your code can then check and tell you if you have any free palette colors available, or if you’ve overrun the limit. Linking this up with a program like <a href="http://www.autohotkey.com/"><strong><span style="color:#0000ff;">Auto Hot Key</span></strong></a> can give you primitive control over importing data back into Zelda3.</li>
</ul>
<p>Personally, I’d try to combine the two. Try to define text/image/binary formats for each of Zelda3’s various data. When possible, keep things “native” (e.g., PNGs) and use a common naming convention (e.g., “Link_4bpp.png”, “Weapons_3bpp.png”) to allow your tools to enforce rules about, say, bit depth, that are hard to enforce using general graphical formats. Then, make Excel macros to import this data and generate whatever views you need. Perhaps, for example, you actually prefer editing maps using Excel. So make a map editor tab. Then, use a Makefile to generate a Zelda3 ROM from your text/binary formats. This allows you to backup into an SVN repository. Moreover, it allows you to play around editing things in Hyrule Magic. I imagine Hyrule Magic will be faster to experiment in than anything you could come up with in Excel. So leverage that. Each tool has a use. To me, Hyrule Magic’s use is more geared towards general editing of Zelda3 than managing a new Zelda3 project. But if you’re content fiddling with it for all eternity, then by all means just skip this section —and make <em><strong>constant backups</strong></em>!</p>
<p>Happy Hacking!</p>
<h2>Addendum</h2>
<p>A few questions were asked after the initial post. They were pretty reasonable, so I pecked away at them for a few days and came up with some answers.</p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Add1"><strong>Addendum: Question: How do I make a number of torches open a door when lit and make them burn out after a period of time if I do not do light them fast enough?</strong></a></h3>
<p>First of all, have a look at this passage from the Perfect Guide:</p>
<p><code style="color:black;"><strong>$04F0-$04FF</strong> Timers for torches. Starts at <strong>#FF</strong> and counts down to <strong>0</strong>. Setting it before the torch is lit is a bad idea. It will not cause a torch to light, nor will it brighten the room. Note that this range probably indicates we can have up to 16 torches in an area.</code></p>
<p>This is in the section on “RAM Data”, and it has some interesting implications:</p>
<ol>
<li>Torches probably burn out on their own.</li>
<li>Apparently we could (with some ASM hacking) make a puzzle in which several torches burn out <em><strong>after different amounts of time</strong></em>. That would be a fun puzzle.</li>
<li>Seems that we can’t have more than 16 torches in one area/puzzle. Be careful! Multiple rooms might still be considered the same “area”; you’ll have to test this.</li>
</ol>
<p>The Guide’s content for torches is a bit sparse (as always), so let’s look at a real example from the game. It’s been a while since I played Zelda3, so the only example I remember is that traumatic moving platform puzzle in Turtle Rock. Open up a clean ROM in Hyrule Magic, and browse to <strong>Entrance 35</strong>. Then, move up and then right until you get to the puzzle room.</p>
<div id="attachment_203" class="wp-caption alignnone" style="width: 206px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_four_torches.png"><img class="size-medium wp-image-203" title="add8_four_torches" src="http://lthzelda.files.wordpress.com/2009/06/add8_four_torches.png?w=196&#038;h=147" alt="This Puzzle Occasionally Appears In My Nightmares" width="196" height="147" /></a><p class="wp-caption-text">This Puzzle Occasionally Appears In My Nightmares</p></div>
<p>Click on the “Torch” button in the lower-right, and then right-click on the map. It seems you can add and delete torches, but there’s no special property stating what these torches do.</p>
<p>Click on the “More” button in the top panel to view the map’s extended properties. Notice the tag “Light torches to open”. Click “cancel.</p>
<div id="attachment_204" class="wp-caption alignnone" style="width: 198px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_light_torches_prop.png"><img class="size-medium wp-image-204" title="add8_light_torches_prop" src="http://lthzelda.files.wordpress.com/2009/06/add8_light_torches_prop.png?w=188&#038;h=125" alt="Note the Entry for &quot;Tag 1&quot;" width="188" height="125" /></a><p class="wp-caption-text">Note the Entry for &quot;Tag 1&quot;</p></div>
<p>Click on the “3” in the “Edit” box and then click once on the door at the top of the screen. You will see that its “Type” is set to “12”. Maybe Type 12 is a door that opens when all torches are lit? Let’s try it out.</p>
<p>Close the Turtle Rock dungeon window and click on <strong>Entrance 7D</strong>. Now, click on the “Torch” option, left-click on the existing torch, and drag it closer to the upper-middle-left door. Save.</p>
<div id="attachment_210" class="wp-caption alignnone" style="width: 200px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_single_torch.png"><img class="size-medium wp-image-210" title="add8_single_torch" src="http://lthzelda.files.wordpress.com/2009/06/add8_single_torch.png?w=190&#038;h=140" alt="Add a Torch in the Upper-Left Corner" width="190" height="140" /></a><p class="wp-caption-text">Add a Torch in the Upper-Left Corner</p></div>
<p>Now, in the “Edit” box, click on layer “3”, and then left-click once on the door near the torch. Now press “M” several times until the “type” changes to 12.</p>
<div id="attachment_205" class="wp-caption alignnone" style="width: 210px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_locked_door.png"><img class="size-medium wp-image-205" title="add8_locked_door" src="http://lthzelda.files.wordpress.com/2009/06/add8_locked_door.png?w=200&#038;h=148" alt="The Door Is Now Locked" width="200" height="148" /></a><p class="wp-caption-text">The Door Is Now Locked</p></div>
<p>Don’t forget to set Tag 1 to “Light torches to open”. Otherwise, lighting the torches won’t affect anything.</p>
<p>Save the ROM, and try it out….  it doesn’t work. Hmm…. a bit of Googling finds this tidbit:</p>
<p><code style="color:black;">“In order for light torches to open door/get chest to work, you'll need exactly 4 torches in the room, no more, no less.”</code> (<a href="http://acmlm.no-ip.org/archive3/newreply.php?id=333&amp;postid=3870"><strong><span style="color:#0000ff;">Source</span></strong></a>)</p>
<p>Good to know. Add three more torches to our room. (Click on “Torch”, then right-click and choose “Insert a torch”.) Make sure you can access all four from the top half of the room. Note that you might have to delete three torches from some other room in the game before Hyrule Magic will allow you to save the game.</p>
<div id="attachment_211" class="wp-caption alignnone" style="width: 212px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_three_more_torches.png"><img class="size-medium wp-image-211" title="add8_three_more_torches" src="http://lthzelda.files.wordpress.com/2009/06/add8_three_more_torches.png?w=202&#038;h=163" alt="Our Three Additional Torches" width="202" height="163" /></a><p class="wp-caption-text">Our Three Additional Torches</p></div>
<p>Save, close, and try it out. Yes! It works!</p>
<div id="attachment_200" class="wp-caption alignnone" style="width: 202px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_door_opens.png"><img class="size-medium wp-image-200" title="add8_door_opens" src="http://lthzelda.files.wordpress.com/2009/06/add8_door_opens.png?w=192&#038;h=167" alt="The Door Behaves As Expected" width="192" height="167" /></a><p class="wp-caption-text">The Door Behaves As Expected</p></div>
<p>Also note that, as expected, the torches extinguish after a certain amount of time.</p>
<h3 style="padding-top:10px;"><a style="text-decoration:none;color:green;" name="Add2"><strong>Addendum: How do I change were link lands when he falls in a hole to a lower level?</strong></a></h3>
<p>There are two types of holes Link can fall in: “Entrances” from the overworld (like the one we just edited, below the bush in Hyrule Castle) and “Multi-Storey” holes inside dungeons. Well, there’s a third type of hole; one that damages you when you fall into it, but your question wasn’t really about that. Your question is about the second type, but I’ll cover both here.</p>
<p>Let’s start with Overworld hole entrances. First, you need to specify <em><strong>which </strong></em>entrance the hole will lead to. Open your Zelda ROM and click on “Overworld” then <strong>Area 1B</strong>. This is the main castle area. Now, click on the “Hole” toolbar item, then find the tag “7D – Hole” on the map screen. The “7D” in the hole’s name refers to the entrance it leads to; remember from the previous question that we opened <strong>Entrance 7D</strong> to edit the room where you find your uncle.</p>
<p>Click once on “7D – Hole” and then use the <strong>N</strong> and <strong>M</strong> keys to change which entrance this refers to. Change it so that that tag now reads “09 – Hole”. Then, save the map.</p>
<div id="attachment_209" class="wp-caption alignnone" style="width: 186px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_overworld_hole.png"><img class="size-medium wp-image-209" title="add8_overworld_hole" src="http://lthzelda.files.wordpress.com/2009/06/add8_overworld_hole.png?w=176&#038;h=129" alt="The Secret Garden Entrance, Modified" width="176" height="129" /></a><p class="wp-caption-text">The Secret Garden Entrance, Modified</p></div>
<p>If you start Zelda3 and walk into that hole, you’ll end up in the Desert Palace. You will “fall” directly onto the main entrance. If you open up <strong>Entrance 09</strong> in the Dungeon tab, go to the “Starting Location” section and change “Y” to, say, <strong>400</strong>, then Link will fall in slightly above the entrance.</p>
<div id="attachment_201" class="wp-caption alignnone" style="width: 202px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_enter_desert_palace.png"><img class="size-medium wp-image-201" title="add8_enter_desert_palace" src="http://lthzelda.files.wordpress.com/2009/06/add8_enter_desert_palace.png?w=192&#038;h=167" alt="You Can Now &quot;Fall&quot; In To the Desert Palace." width="192" height="167" /></a><p class="wp-caption-text">You Can Now &quot;Fall&quot; In To the Desert Palace.</p></div>
<p>However, he will also appear in this spot when he walks in from the outside door, which will look weird (try walking out then in). So how can we fix this? Well, we’d need to use two Entrances: one for falling in, and one for walking in. Notice how the Hyrule Castle area uses <strong>Entrance 7D</strong> for falling in, and <strong>Entrance 32</strong> for walking in. They both lead to the same room, but with different “Starting Locations”.</p>
<p>So how about multi-level dungeons? The Perfect Guide has this to say about holes in dungeons, in the “Room Information and Properties” section:</p>
<p><code style="color:black;"><strong>Hole/Warp</strong>: Directs the holes or warp tiles. When you fall through a floor or warp to another room it will always be in the exact place in the new room as you left in the old.</code></p>
<p>To see this in action, open <strong>Entrance 33</strong>, the Tower of Hera, and click on the “More” button in the top panel.</p>
<div id="attachment_207" class="wp-caption alignnone" style="width: 209px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_mountain_palace_entrance.png"><img class="size-medium wp-image-207" title="add8_mountain_palace_entrance" src="http://lthzelda.files.wordpress.com/2009/06/add8_mountain_palace_entrance.png?w=199&#038;h=146" alt="The Tower's Map Properties Dialog" width="199" height="146" /></a><p class="wp-caption-text">The Tower&#39;s Map Properties Dialog</p></div>
<p>Notice the “Hole/Warp” box has a value of 167? This is where you land if you fall into the big jars in the top part of the room. Just to spice things up, let’s add a new hole to fall into. Click on the “2” in the “Edit” tab, then right-click near the entrance and choose “Insert an Object”. Browse to object <strong>0A4</strong>, and click “Ok”. Then, drag it somewhere noticeable, and save.</p>
<div id="attachment_208" class="wp-caption alignnone" style="width: 202px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_mountain_palace_floor_damage.png"><img class="size-medium wp-image-208" title="add8_mountain_palace_floor_damage" src="http://lthzelda.files.wordpress.com/2009/06/add8_mountain_palace_floor_damage.png?w=192&#038;h=141" alt="Our Main Entrance Is Now Hazardous!" width="192" height="141" /></a><p class="wp-caption-text">Our Main Entrance Is Now Hazardous!</p></div>
<p>Click the “Jump” button and type in <strong>167</strong> to go to the target of the hole. Now, insert an object (any object) near the bottom of the screen, on layer 1, so that we can test if you fell into the right room. Save.</p>
<div id="attachment_206" class="wp-caption alignnone" style="width: 226px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_marker_chest.png"><img class="size-medium wp-image-206" title="add8_marker_chest" src="http://lthzelda.files.wordpress.com/2009/06/add8_marker_chest.png?w=216&#038;h=170" alt="Add Anything, Just So We Can Tell If We Landed In the Right Room" width="216" height="170" /></a><p class="wp-caption-text">Add Anything, Just So We Can Tell If We Landed In the Right Room</p></div>
<p>Now, go back to overworld area <strong>1B</strong>, and change the hole under the bush to lead to <strong>Entrance 33</strong>. Save, and start the game. Fall into the first hole (near the castle) to warp to the mountain palace…</p>
<div id="attachment_212" class="wp-caption alignnone" style="width: 209px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_warp_to_first_floor.png"><img class="size-medium wp-image-212" title="add8_warp_to_first_floor" src="http://lthzelda.files.wordpress.com/2009/06/add8_warp_to_first_floor.png?w=199&#038;h=173" alt="The Shortest Distance Between Two Points Is a Modified Entrance." width="199" height="173" /></a><p class="wp-caption-text">The Shortest Distance Between Two Points Is a Modified Entrance.</p></div>
<p>…and fall into the second hole to test that you end up at the <em><strong>exact same location</strong></em> in room 167.</p>
<div id="attachment_202" class="wp-caption alignnone" style="width: 230px"><a href="http://lthzelda.files.wordpress.com/2009/06/add8_falling_to_success.png"><img class="size-medium wp-image-202" title="add8_falling_to_success" src="http://lthzelda.files.wordpress.com/2009/06/add8_falling_to_success.png?w=220&#038;h=192" alt="We Landed In Our Abandoned Room" width="220" height="192" /></a><p class="wp-caption-text">We Landed In Our Abandoned Room</p></div>
<p>So there you have it! Zelda3’s all about room/dungeon/nonsense management, and warp tiles/holes are just another great example of where a little knowledge goes a long way.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/169/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=169&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2009/06/24/lz-3-intermediate-hyrule-magic/feed/</wfw:commentRss>
		<slash:comments>51</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_links_graphics.png?w=300" medium="image">
			<media:title type="html">post8_links_graphics</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_my_link_helmet.png?w=300" medium="image">
			<media:title type="html">post8_my_link_helmet</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_link_swims.png?w=300" medium="image">
			<media:title type="html">post8_link_swims</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_hm_error.png?w=300" medium="image">
			<media:title type="html">post8_hm_error</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_graphics_gale_palette_menu.png?w=194" medium="image">
			<media:title type="html">post8_graphics_gale_palette_menu</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_copying_a_palette.png?w=300" medium="image">
			<media:title type="html">post8_copying_a_palette</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_editing_mushroomboy.png?w=300" medium="image">
			<media:title type="html">post8_editing_mushroomboy</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_shield_located.png?w=300" medium="image">
			<media:title type="html">post8_shield_located</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_face_shield.png?w=300" medium="image">
			<media:title type="html">post8_face_shield</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_skull_shield_uncle.png?w=300" medium="image">
			<media:title type="html">post8_skull_shield_uncle</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_flute_boys_grotto.png?w=300" medium="image">
			<media:title type="html">post8_flute_boys_grotto</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_selecting_a_tile.png?w=300" medium="image">
			<media:title type="html">post8_selecting_a_tile</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_32x32_editor.png?w=300" medium="image">
			<media:title type="html">post8_32x32_editor</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_16x16_editor.png?w=300" medium="image">
			<media:title type="html">post8_16x16_editor</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_changing_16x16_tiles.png?w=300" medium="image">
			<media:title type="html">post8_changing_16x16_tiles</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_palette_screwiness.png?w=300" medium="image">
			<media:title type="html">post8_palette_screwiness</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_save_prompt.png?w=300" medium="image">
			<media:title type="html">post8_save_prompt</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_rocks_rock.png?w=300" medium="image">
			<media:title type="html">post8_rocks_rock</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_viewing_flute_locations.png?w=300" medium="image">
			<media:title type="html">post8_viewing_flute_locations</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_moving_the_maps_flute_point.png?w=300" medium="image">
			<media:title type="html">post8_moving_the_maps_flute_point</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_removing_the_old_flute_point.png?w=300" medium="image">
			<media:title type="html">post8_removing_the_old_flute_point</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_inserting_a_new_flute_location.png?w=300" medium="image">
			<media:title type="html">post8_inserting_a_new_flute_location</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_using_the_new_flute.png?w=300" medium="image">
			<media:title type="html">post8_using_the_new_flute</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_warping_in_with_the_flute.png?w=300" medium="image">
			<media:title type="html">post8_warping_in_with_the_flute</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_unintended_flute_consequences.png?w=300" medium="image">
			<media:title type="html">post8_unintended_flute_consequences</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_3d_movement.png?w=300" medium="image">
			<media:title type="html">post8_3d_movement</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_3d_point.png?w=300" medium="image">
			<media:title type="html">post8_3d_point</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_triangle_diagram.png?w=300" medium="image">
			<media:title type="html">post8_triangle_diagram</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_hexagon_diagram.png?w=300" medium="image">
			<media:title type="html">post8_hexagon_diagram</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_moving_the_first_point.png?w=300" medium="image">
			<media:title type="html">post8_moving_the_first_point</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_first_face.png?w=300" medium="image">
			<media:title type="html">post8_first_face</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_single_hexagon.png?w=300" medium="image">
			<media:title type="html">post8_single_hexagon</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_added_2_faces.png?w=300" medium="image">
			<media:title type="html">post8_added_2_faces</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_final_coin.png?w=300" medium="image">
			<media:title type="html">post8_final_coin</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_final_coin_in_emu.png?w=300" medium="image">
			<media:title type="html">post8_final_coin_in_emu</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_rainbow_triforce.png?w=300" medium="image">
			<media:title type="html">post8_rainbow_triforce</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_overworld_properties.png?w=300" medium="image">
			<media:title type="html">post8_overworld_properties</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_setting_a_key.png?w=300" medium="image">
			<media:title type="html">post8_setting_a_key</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_choose_location_menu.png?w=300" medium="image">
			<media:title type="html">post8_choose_location_menu</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_adding_a_new_block.png?w=300" medium="image">
			<media:title type="html">post8_adding_a_new_block</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_coloring_block_1.png?w=300" medium="image">
			<media:title type="html">post8_coloring_block_1</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_initial_logo_placement_in_editor.png?w=300" medium="image">
			<media:title type="html">post8_initial_logo_placement_in_editor</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_logo_placed_in_zsnes.png?w=300" medium="image">
			<media:title type="html">post8_logo_placed_in_zsnes</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_copy_menu_titles.png?w=300" medium="image">
			<media:title type="html">post8_copy_menu_titles</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post8_add_logo.png?w=300" medium="image">
			<media:title type="html">post8_add_logo</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_four_torches.png?w=300" medium="image">
			<media:title type="html">add8_four_torches</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_light_torches_prop.png?w=300" medium="image">
			<media:title type="html">add8_light_torches_prop</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_single_torch.png?w=300" medium="image">
			<media:title type="html">add8_single_torch</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_locked_door.png?w=300" medium="image">
			<media:title type="html">add8_locked_door</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_three_more_torches.png?w=300" medium="image">
			<media:title type="html">add8_three_more_torches</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_door_opens.png?w=300" medium="image">
			<media:title type="html">add8_door_opens</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_overworld_hole.png?w=300" medium="image">
			<media:title type="html">add8_overworld_hole</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_enter_desert_palace.png?w=300" medium="image">
			<media:title type="html">add8_enter_desert_palace</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_mountain_palace_entrance.png?w=300" medium="image">
			<media:title type="html">add8_mountain_palace_entrance</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_mountain_palace_floor_damage.png?w=300" medium="image">
			<media:title type="html">add8_mountain_palace_floor_damage</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_marker_chest.png?w=300" medium="image">
			<media:title type="html">add8_marker_chest</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_warp_to_first_floor.png?w=300" medium="image">
			<media:title type="html">add8_warp_to_first_floor</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/add8_falling_to_success.png?w=300" medium="image">
			<media:title type="html">add8_falling_to_success</media:title>
		</media:content>
	</item>
		<item>
		<title>[RM-3] Speech Balloons That “Type” Their Message</title>
		<link>http://lthzelda.wordpress.com/2009/06/05/rm-3-speech-balloons-that-%e2%80%9ctype%e2%80%9d-their-message/</link>
		<comments>http://lthzelda.wordpress.com/2009/06/05/rm-3-speech-balloons-that-%e2%80%9ctype%e2%80%9d-their-message/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 01:58:39 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=97</guid>
		<description><![CDATA[Blog Info: I’m mostly done reading a great 65816 (SNES) assembly guide; this guide is so sensibly written that I think I&#8217;m actually ready to do a fun text hack for my favorite game of all time. So this week’s &#8230; <a href="http://lthzelda.wordpress.com/2009/06/05/rm-3-speech-balloons-that-%e2%80%9ctype%e2%80%9d-their-message/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=97&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><strong><em>Blog Info</em></strong>: I’m mostly done reading a great <a href="http://catalog.loc.gov/cgi-bin/Pwebrecon.cgi?DB=local&amp;CNT=25+records+per+page&amp;CMD=isbn+0893037893"><span style="color:#0000ff;">65816 (SNES) assembly guide</span></a>; this guide is so sensibly written that I think I&#8217;m actually ready to do a fun text hack for my <a href="http://shrines.rpgclassics.com/snes/lufia2/"><span style="color:#0000ff;">favorite game of all time</span></a>. So this week’s hack will help me prepare by introducing the algorithm in a high-level language. Plus, I think the RPG Maker community will like this one.</p>
<p><strong><em>Back-story</em></strong>:  Ok, our last attempt at speech balloons kind of flopped. They stretched text, they jittered, and they just popped into existence. Their worst sin, in my opinion, is that they didn’t “open” like the default RPG Maker ones, nor could they “type” their text out letter by letter. Let’s fix everything in one fell swoop.</p>
<p><strong><em>Goal</em></strong>: Spruce up our speech balloon code, particularly in regards to opening/closing them when the player walks within range, and typing their message text out letter-by-letter.</p>
<p>You should read through <a href="http://lthzelda.wordpress.com/2009/02/24/rm-2-speech-balloons-for-npcs/"><span style="color:#0000ff;">tutorial RM-2</span></a> before starting this task. Instead of using a clean (new) project, I’m going to start where we left off after that tutorial. Don’t worry, I flushed my own project and copied it letter-for-letter from RM-2. One thing to note:</p>
<ul>
<li>Your “Talkbox_Window” module needs to be in a location that the interpreter can find. For example, add it below the “Windows” tab, or “Materials”. If you just add it anywhere (say, at  the end of the file), you might get an error when you try to run the program.</li>
</ul>
<p>I added this factoid to the original article, too. People, please <em>tell </em>me if you can’t get your code to work following one of my guides; I&#8217;ll be happy to fix it.</p>
<p><strong>Step 1: Variable Width and Jitter Reduction</strong><br />
Add the following line to “Main” right after Graphics.freeze:</p>
<pre><code style="color:black;">$Debug = Window_Base.new(544, 0, 544, 416)
$Debug.windowskin = nil
</code></pre>
<p>This just gives us an “offscreen” area to calculate stuff on. If you’re combining tutorial <a href="http://lthzelda.wordpress.com/2009/02/07/rm-1-a-debug-window/"><span style="color:#0000ff;">RM-1</span></a> with RM-2, you can ignore this, and just use the regular $Debug window for offscreen stuff.</p>
<p>Replace the Talkbox_Window class with the following one:</p>
<pre><code style="color:black;"><span style="color:green;">#A slightly improved RM-2 talkbox</span>
class Talkbox_Window &lt; Window_Base
  <span style="color:green;">#RPG Maker defaults</span>
  MAX_WINDOW_WIDTH = 544
  MAX_WINDOW_HEIGHT = 416
  WINDOW_PADDING = 32

  <span style="color:green;">#npc is a GameEvent</span>
  def initialize(npc, txt)
    <span style="color:green;">#Figure out a proper size, and initialize it offscreen</span>
    my_size = $Debug.contents.text_size(txt)
    super(0, 0,
       my_size.width + WINDOW_PADDING,
       my_size.height + WINDOW_PADDING)

    <span style="color:green;">#Put off setting this variable until later</span>
    @offset_y = -1

    <span style="color:green;">#On top and invisible</span>
    self.z = 90
    self.visible = false

    <span style="color:green;">#Draw the text once</span>
    self.contents.draw_text(0, 0, draw_width, draw_height, txt)
  end

  <span style="color:green;">#Call this to update the talkbox’s position over an NPC</span>
  def update_pos(npc)
    <span style="color:green;">#Store the npc’s height if we haven’t done so yet</span>
    @offset_y = npc.sprite_height if @offset_y==-1

    <span style="color:green;">#Update this talkbox’s position</span>
    self.x = npc.screen_x - self.width/2
    self.y = npc.screen_y - self.height - @offset_y
  end

  <span style="color:green;">#Get the width of the client area</span>
  def draw_width
    return self.width - WINDOW_PADDING
  end

  <span style="color:green;">#Get the height of the client area</span>
  def draw_height
    return self.height - WINDOW_PADDING
  end
end</code></pre>
<p>The MAX_WINDOW_WIDTH and MAX_WINDOW_HEIGHT variables just happen to be the window sizes RPG Maker ships with. I couldn’t for the life of me find these anywhere in the documentation, so I just stored my own values here. The DEFAULT_PADDING represents how much space is used as “border space” by any RPG Maker window —if you don’t add this value to each window you create, you may  find that everything you draw  is “cut off”.</p>
<p>We cache the return value of sprite_height because we’re worried it will affect performance. We’ll describe why later.</p>
<p>The remainder of the code is pretty simple to understand, even though not all relevant functions have been implemented yet. We’re basically resizing the talkbox to hold all of its text, and centering it above the NPC in question.</p>
<p>Now we need to add all those missing functions. Open Game_Event and add the following two member definitions:</p>
<pre><code style="color:black;">  def sprite_width
    <span style="color:green;">#Easy if this is a tile-based event</span>
    return 32 if @tile_id &gt; 0

    <span style="color:green;">#Harder if this is a sprite</span>
    unless $scene.is_a?(Scene_Map)
      return 0   <span style="color:#008000;">#A generic Scene isn’t good enough
</span>    end
    return $scene.get_event_width(self)
  end

  def sprite_height
    <span style="color:green;">#Easy if this is a tile-based event</span>
    return 32 if @tile_id &gt; 0

    <span style="color:green;">#Harder if this is a sprite</span>
    unless $scene.is_a?(Scene_Map)
      return 0   <span style="color:#008000;">#A generic Scene isn’t good enough
</span>    end
    return $scene.get_event_height(self)
  end
</code></pre>
<p>There’s probably a better way to get this information, but this will have to do until I get a chance to read all the RMVX documentation. Basically, we just return the size of a tile or the size of a sprite depending on what this event is represented by. Of course, our caching code will position talkboxes improperly if you keep changing your event’s graphics from a Tile to a Chara representation. You can remove the caching if this bothers you, but I find it to be an unlikely edge case.</p>
<p>As you might have guessed, we now have to edit Scene_Map. Add the following functions anywhere:</p>
<pre><code style="color:black;">  def get_event_width(event)
    return @spriteset.get_event_sprite(event).width
  end
  def get_event_height(event)
    return @spriteset.get_event_sprite(event).height
  end
</code></pre>
<p>Often, you’ll find that the Scene_* classes contain the down-and-dirty details of the game engine, while the Game_* classes contain a higher-level “logical” set of data points. Why, I’d bet we could fix the screen jitter we discovered earlier by simply updating talkboxes <em>here </em>instead of in Game_Map. This is completely correct. Find the following line in Game_Map&#8217;s &#8220;update&#8221; method:</p>
<pre><code style="color:black;">    update_talkboxes</code></pre>
<p>&#8230;and remove it. Then, add the following line to Scene_Map&#8217;s &#8220;update&#8221; method, right <em>after</em> &#8220;@message_window.update&#8221;.</p>
<pre><code style="color:black;">    $game_map.update_talkboxes   <span style="color:#008000;">#Update NPC talkboxes</span></code></pre>
<p>That&#8217;ll fix the 1-pixel jitter we noticed earlier. Why? My guess is that “@spriteset.update” (which occurs after “$game_map.update”) does a minor pixel correction on every sprite that’s scrolling. For Game_Map’s objects, this tiny offset isn’t important.</p>
<p>By the way, a lot of game objects have both a Game_* and a Sprite_* representation. We might consider doing the same thing for our windows; then we wouldn’t need this minor hack. However, I don’t think it’s important.</p>
<p>Add the following function to Spriteset_Map. The explicit loop this function contains, by the way, is the reason we cache @offset_y.</p>
<pre><code style="color:black;">  def get_event_sprite(event)
    for character in @character_sprites
      return character if character.for_event?(event)
    end
  end</code></pre>
<p>Finally, add the for_event? function to Sprite_Character:</p>
<pre><code style="color:black;">  def for_event?(event)
    return event == @character
  end</code></pre>
<p>All this is rather hackish, but it’s self-contained, so I don’t consider it such a sin. More importantly, it makes our talkboxes work! Create a few NPCs and give them long-ish textboxes. Have them walk around if you want. Start a new game and enjoy the much, much nicer talkboxes (note the walking cow).</p>
<div id="attachment_101" class="wp-caption alignnone" style="width: 217px"><a href="http://lthzelda.files.wordpress.com/2009/06/post7_boxes_plus_plus.png"><img class="size-medium wp-image-101" title="post7_boxes_plus_plus" src="http://lthzelda.files.wordpress.com/2009/06/post7_boxes_plus_plus.png?w=207&#038;h=167" alt="Our New Boxes Auto-Size and Don't Jitter When You Walk." width="207" height="167" /></a><p class="wp-caption-text">Our New Boxes Auto-Size and Don&#39;t Jitter When You Walk.</p></div>
<p>Don’t worry about the fact that boxes appear on the map for a split second before moving above their respective NPCs; we’ll eventually start them all “closed”, which will fix this problem.</p>
<p><strong>Step 2: Opening Boxes When In Range</strong></p>
<p>We&#8217;ve come a long way, but  our talkboxes still need some major work. For one thing, it doesn’t make sense to show them all on-screen at once. Besides introducing an unnecessary bottleneck, this is also rather boring to look at from the player&#8217;s perspective. So, let’s start all talkboxes “closed” and then “open” them when an NPC steps into the farthest visible tiles. (We’ll close them if he steps out of bounds).</p>
<p>This will require oodles of code to be written. Phase one will be to make the windows open and type their text; the second phase will invoke this code when an NPC steps into bounds. We will borrow most of our new code from Window_Message. Here’s our new class:</p>
<pre><code style="color:black;"><span style="color:green;">#A version of a Message which appears over a single
# NPC’s head. Supports most text tags, and auto-sizing.</span>
class Talkbox_Window &lt; Window_Base
  <span style="color:green;">#RPG Maker defaults</span>
  MAX_WINDOW_WIDTH = 544
  MAX_WINDOW_HEIGHT = 416
  WINDOW_PADDING = 32

  <span style="color:green;">#Create a new Talkbox_Window.
  #  @param npc – The GameEvent above which we show our talkbox
  #  @param txt – A String (or array of strings) which
  #               represents our message. (Arrays aren’t yet
  #               supported).</span>
  def initialize(npc, txt)
    <span style="color:green;">#Figure out a proper size, and initialize it offscreen
    #  Height is +3 to allow for g/p/y/etc.</span>
    my_size = $Debug.contents.text_size(txt)
    super(0, 0,
       my_size.width + WINDOW_PADDING,
       my_size.height + 3 + WINDOW_PADDING)

    <span style="color:green;">#Put off setting this variable until later</span>
    @offset_y = -1

    <span style="color:green;">#On top and invisible</span>
    self.z = 90
    self.visible = false

    <span style="color:green;">#Fully shrunken, and neither opening nor closing.</span>
    self.openness = 0
    @opening = false
    @closing = false

    <span style="color:green;">#Pause after opening? Note that we can’t use
    # self.pause; that'll set a bouncing graphic</span>
    @passive_pause = false

    <span style="color:green;">#Reset variables used to track the state of the
    # drawing routine</span>
    @text = nil       <span style="color:green;">#Our text buffer</span>
    @contents_x = 0   <span style="color:green;">#Next character’s X</span>
    @contents_y = 0   <span style="color:green;">#Next character’s Y</span>
    @line_count = 0   <span style="color:green;">#Lines drawn so far</span>
    @wait_count = 0   <span style="color:green;">#How long to pause (for \., etc.)</span>
    @line_show_fast = false

    <span style="color:green;">#Save our text-to-draw</span>
    @orig_texts = Array(txt)
   end

  <span style="color:green;">#
  # New functionality for text processing
  # </span>

  <span style="color:green;">#Frame Update – All opening/closing/typing happens here</span>
  def update
    <span style="color:green;">#Handle opening/closing</span>
    super

    <span style="color:green;">#All other actions must wait for a fully-opened window</span>
    unless @opening or @closing
      if @wait_count &gt; 0
        <span style="color:green;">#We’re pausing _within_ the text stream</span>
        @wait_count -= 1
      elsif @passive_pause
        <span style="color:green;">#The window is fully open; leave it open
        # (optionally, we can add code to scan for Input)</span>
      elsif @text != nil
        <span style="color:green;">#There's text we haven’t shown yet</span>
        update_message
      elsif continue?
        <span style="color:green;">#Open the window and show its text</span>
        start_message
        open
      end
    end
  end

  <span style="color:green;">#Start a new line of text</span>
  def new_line
    @contents_x = 0
    @contents_y += WLH
    @line_count += 1
    @line_show_fast = false
  end

  <span style="color:green;">#Should we be displaying the next message?
  # For now, the answer is “always”, but you can add your
  # own control code if you like</span>
  def continue?
    return true
  end

  <span style="color:green;">#Align all our text for processing into a single string with
  # embedded control characters</span>
  def start_message
    @text = ""
    for i in 0...@orig_texts.size
      @text += @orig_texts[i].clone + "\x00"
    end
    convert_special_characters
    new_page
  end

  <span style="color:green;">#Replace all special letters with single-character</span>
  <span style="color:green;"># equivalents. (Copied verbatim from Message)</span>
  def convert_special_characters
    @text.gsub!(/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] }
    @text.gsub!(/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] }
    @text.gsub!(/\\N\[([0-9]+)\]/i) { $game_actors[$1.to_i].name }
    @text.gsub!(/\\C\[([0-9]+)\]/i) { "\x01[#{$1}]" }
    @text.gsub!(/\\G/)              { "\x02" }
    @text.gsub!(/\\\./)             { "\x03" }
    @text.gsub!(/\\\|/)             { "\x04" }
    @text.gsub!(/\\!/)              { "\x05" }
    @text.gsub!(/\\&gt;/)              { "\x06" }
    @text.gsub!(/\\&lt;/)              { "\x07" }
    @text.gsub!(/\\\^/)             { "\x08" }
    @text.gsub!(/\\\\/)             { "\\" }
  end

  <span style="color:green;">#Start a new “page” of input on the current message
  # box’s surface. Right now, we only have one page of
  # input, but there’s no reason you can’t add more.</span>
  def new_page
    <span style="color:green;">#Clear the background bitmap</span>
    self.contents.clear

    <span style="color:green;">#Reset our drawing state variables</span>
    @contents_x = 0
    @contents_y = 0
    @line_count = 0
    @line_show_fast = false
    @passive_pause = false

    <span style="color:green;">#Reset our text color to the default</span>
    contents.font.color = text_color(0)
  end  

  <span style="color:green;">#Called when a message has been printed in its entirety
  # (used below)</span>
  def finish_message
    @passive_pause = true
    @wait_count = 10
    @text = nil
  end

  <span style="color:green;">#This is the main text processing loop of the talkbox window.
  # It works by slicing one character at a time off of @text,
  # and either reacting to it as a control character,
  # or displaying it.</span>
  def update_message
    loop do
      <span style="color:green;">#Get next text character</span>
      c = @text.slice!(/./m)
      case c
        when nil
          <span style="color:green;">#There is no text waiting to be drawn</span>
          finish_message
          break
        when "\x00"
          <span style="color:green;">#Our custom "newline" character</span>
          new_line
          <span style="color:green;">#Multiple pages; left in for your reference
          #if @line_count &gt;= MAX_LINE
          #  unless @text.empty?
          #    self.pause = true
          #    break
          #  end
          #end</span>
      when "\x01"
        <span style="color:green;">#\C[n]  (text character color change)</span>
        @text.sub!(/\[([0-9]+)\]/, "")
        contents.font.color = text_color($1.to_i)
        next
      when "\x02"
        <span style="color:green;">#\G  (gold display) -ignore</span>
        break
      when "\x03"
        <span style="color:green;">#\.  (wait 1/4 second)</span>
        @wait_count = 15
        break
      when "\x04"
        <span style="color:green;">#\|  (wait 1 second)</span>
        @wait_count = 60
        break
      when "\x05"
        <span style="color:green;">#\!  (Wait for input)</span>
        break
      when "\x06"
        <span style="color:green;">#\&gt;  (Fast display ON)</span>
        @line_show_fast = true
      when "\x07"
        <span style="color:green;">#\&lt;  (Fast display OFF)</span>
        @line_show_fast = false
      when "\x08"
        <span style="color:green;">#\^  (No wait for input)</span>
        break
      else
        <span style="color:green;">#Normal text character</span>
        contents.draw_text(@contents_x, @contents_y, 40, WLH, c)
        c_width = contents.text_size(c).width
        @contents_x += c_width
      end
      break unless @line_show_fast
    end
  end

  <span style="color:green;">#
  # The rest of our functionality is unchanged
  #</span>

  <span style="color:green;">#Call this to update the talkbox’s position over an NPC</span>
  def update_pos(npc)
    <span style="color:green;">#Store the npc’s height if we haven’t done so yet</span>
    @offset_y = npc.sprite_height if @offset_y==-1

    <span style="color:green;">#Update this talkbox’s position</span>
    self.x = npc.screen_x - self.width/2
    self.y = npc.screen_y - self.height - @offset_y
  end

  <span style="color:green;">#Get the width/height of the client area</span>
  def draw_width
    return self.width - WINDOW_PADDING
  end
  def draw_height
    return self.height - WINDOW_PADDING
  end
end</code></pre>
<p>What a whopper! Fortunately, this is fairly easy to understand: update() determines whether or not we should be calling update_message(), which reads letters one-by-one. All other methods are helpers, and their functions are relatively simple. I’ve got to hand it to the RPG Maker VX team: their code might be a bit cluttered, but it’s very easy to follow and understand. I’m consistently amazed at how sensible it is to hack the RPGMVX engine.</p>
<p>Now, add the following code in Game_Event’s update() method, right below check_event_trigger_auto:</p>
<pre><code style="color:black;"><span style="color:green;">#Update NPC talkbox</span>
@npc_talkbox.update if @npc_talkbox != nil
</code></pre>
<p>This is much easier to understand; we just needed to hook up our frame update method when the Game Event calls its update method. Finally, add a new event to your map, with the following “Script” command:</p>
<pre><code style="color:black;">for event in $game_map.events.values
  tkb = event.npc_talkbox
  next unless tkb
  tkb.openness = 0
  tkb.start_message()
  tkb.open()
end</code></pre>
<p>Since windows stay open forever, we need a way to “re-type” the window, to make sure our system is working properly. Since we didn’t bother writing such a method (we will later), we just hooked it up manually for now.</p>
<p>Run your program; talk to your new NPC any time you want to reset every window. Ah…. Isn’t that nice? As an added benefit, our windows no longer show up on the title screen, since their &#8220;openness&#8221; only gets updated in the main game loop.</p>
<div id="attachment_102" class="wp-caption alignnone" style="width: 228px"><a href="http://lthzelda.files.wordpress.com/2009/06/post7_self-typing_boxes.png"><img class="size-medium wp-image-102" title="post7_self-typing_boxes" src="http://lthzelda.files.wordpress.com/2009/06/post7_self-typing_boxes.png?w=218&#038;h=177" alt="These TalkBoxes Show Their Messages Just Like a Normal RPGMVX Show_Message Box." width="218" height="177" /></a><p class="wp-caption-text">These TalkBoxes Show Their Messages Just Like a Normal RPGMVX Show_Message Box.</p></div>
<p>Before we make these talkboxes appear on demand, we have to decide <em>when</em> exactly we want to show them. I chose to wait for a talkbox to be fully onscreen vertically, and halfway onscreen horizontally before starting to open it. I made this decision partly because boxes are centered over NPCs, so a talkbox will now appear slightly before or after its respective NPC becomes visible. Add the following function to your Window_Talkbox class; it checks whether or not this box should be opened:</p>
<pre><code style="color:black;"><span style="color:green;">  #Is this box within the vertical boundaries, and at
  # least halfway within the horizontal boundaries?</span>
  def in_range?
    <span style="color:green;">#Store some marker variables</span>
    mid_x = self.x+self.width/2
    min_y = self.y
    max_y = self.y+self.height

    <span style="color:green;">#Check bounds</span>
    return true if min_y&gt;=0 and mid_x&gt;=0 and
                   max_y&lt;=MAX_WINDOW_HEIGHT and
                   mid_x&lt;=MAX_WINDOW_WIDTH
    return false
  end</code></pre>
<p>As you should have noticed, this function relies on the update_pos() function being called first. And, if you think about it, update_pos doesn’t work unless called in the Scene_* routine; calling it in the context of Game_* is a mistake. So, instead of juggling a whole slew of function calls, we&#8217;ll just append our code to update_pos(). Your update_pos function should now look like this:</p>
<pre><code style="color:black;"><span style="color:green;">  #Call this to update the talkbox’s position over an NPC</span>
  def update_pos(npc)
    <span style="color:green;">#Store the npc’s height if we haven’t done so yet</span>
    @offset_y = npc.sprite_height if @offset_y==-1

    <span style="color:green;">#Update this talkbox’s position</span>
    self.x = npc.screen_x - self.width/2
    self.y = npc.screen_y - self.height - @offset_y

    <span style="color:green;">#Now, show/hide we show this box?</span>
    if @onscreen != in_range?
      unless @onscreen
        retype_text()
      else
        close_window()
      end
    end
  end</code></pre>
<p>This relies on a new variable, @onscreen. Add it to your init function (anywhere)</p>
<pre><code style="color:black;">@onscreen = false  <span style="color:green;">#In-range?</span></code></pre>
<p>Finally, you’ll need the functions retype_text() and close_window(). Add them anywhere:</p>
<pre><code style="color:black;">def retype_text
  @onscreen = true
  openness = 0
  start_message()
  open()
end

def close_window
  @onscreen = false
  close
end</code></pre>
<p>This should do the trick. The only thing left to do is to find the following lines in update’s “elsif continue?” branch and comment them out:</p>
<pre><code style="color:black;"><span style="color:green;">  # start_message
  # open</span></code></pre>
<p>…otherwise, the window will always open itself, regardless of its position onscreen. Run your code:</p>
<div id="attachment_103" class="wp-caption alignnone" style="width: 237px"><a href="http://lthzelda.files.wordpress.com/2009/06/post7_self-typing_boxes_that_open.png"><img class="size-medium wp-image-103" title="post7_self-typing_boxes_that_open" src="http://lthzelda.files.wordpress.com/2009/06/post7_self-typing_boxes_that_open.png?w=227&#038;h=182" alt="Our Boxes Now Open When In Range, Completing Our Original Goal." width="227" height="182" /></a><p class="wp-caption-text">Our Boxes Now Open When In Range, Completing Our Original Goal.</p></div>
<p>The nice thing is, since we check this every tick (instead of just when the NPC moves) it should work properly for teleporting to a new map and teleporting NPCs around the map.</p>
<p><em>Note: </em>The documentation states that if a Window&#8217;s &#8220;openness&#8221; value is less than 255, its &#8220;contents&#8221; Bitmap won&#8217;t be displayed. I am kind of assuming that, if its &#8220;openness&#8221; is 0, the windowskin also won&#8217;t be displayed, and processing will be minimal. I feel this is a safe assumption, but I want to make it clear that, if you experience a performance hit, you might want to look here first.</p>
<p><strong><em>Possible Improvements</em></strong></p>
<p>This tutorial was rather longish, so I&#8217;ll only give you two assignments this week.</p>
<ul>
<li>It’s well known that inheritance simplifies code reuse. Yet, rather than reusing the code in Window_Message, we just copied it and deleted what we didn’t want. Wouldn’t it be better to abstract it into a common superclass, and have both Window_Message and Window_Talkbox subclass this new class? For our tutorial: no. Extracting this code could have broken<em> both </em>normal messages <em>and </em>our talkboxes. Our lightweight class only risks breaking itself, which makes it ideal for development. Now that we’re done proving the concept, however, it would be a good idea to create a common superclass. That’s your first assignment.</li>
<li>We copied the convert_special_characters() function directly from Window_Message, but closer inspection makes it clear that only a small number of backslashed “special letters” are used. Might we extend the list of possible escape sequences? Since we extract the text for our message balloon directly from a ShowMessage event, this provides a very elegant way of specifying additional properties of talkboxes. For example, we might use \{ACCEPT} to mean “this talkbox responds to the Accept key”, and \{EVENT:2} to mean “call event 2 when the user presses Accept”. Perhaps \{CLOSE:10} could means “close this talkbox 10 ticks after all text has been displayed” —indeed, we’ll need a lot more control if we’re to use these things for cutscenes.</li>
</ul>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/97/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/97/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/97/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/97/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/97/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/97/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/97/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/97/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/97/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/97/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/97/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/97/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/97/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/97/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=97&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2009/06/05/rm-3-speech-balloons-that-%e2%80%9ctype%e2%80%9d-their-message/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post7_boxes_plus_plus.png?w=300" medium="image">
			<media:title type="html">post7_boxes_plus_plus</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post7_self-typing_boxes.png?w=300" medium="image">
			<media:title type="html">post7_self-typing_boxes</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/06/post7_self-typing_boxes_that_open.png?w=300" medium="image">
			<media:title type="html">post7_self-typing_boxes_that_open</media:title>
		</media:content>
	</item>
		<item>
		<title>[REV-1] Current Exciting Hacks</title>
		<link>http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/</link>
		<comments>http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/#comments</comments>
		<pubDate>Mon, 01 Jun 2009 04:48:16 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=81</guid>
		<description><![CDATA[Blog Info: I&#8217;m in a bit of a rut, time-wise. My latest project just developed a huge bug, and my current research project is also eating up a lot of time. I could tell you my plans for future blog &#8230; <a href="http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=81&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em><strong>Blog Info:</strong> I&#8217;m in a bit of a rut, time-wise. My <a href="http://www.waitzar.com/">latest project</a> just developed a huge bug, and my current research project is also eating up a lot of time. I <strong>could </strong>tell you my plans for future blog posts, but I&#8217;m notorious for changing my mind. Instead, I&#8217;ve got a much better idea!<br />
</em></p>
<p><strong><em>Back-story:</em></strong> We&#8217;ve been hacking away for a while; it&#8217;s time to take a second and reflect on hacks that <em>other</em> people in the gaming community are working on. To me, this is always a rewarding experience: you&#8217;ll find a lot of really creative and exciting ideas out there, and you&#8217;ll be able to refine your own ideas a bit too. This week, we&#8217;ll focus on ROM hacks, particularly my penchants of Mario and Zelda. Where possible, I&#8217;ll provide videos.</p>
<p><strong><em>Super Mario Odyssey</em></strong><br />
<strong>Summary:</strong> A thorough hack of Super Mario World that somehow presents itself as &#8220;just a simple hack&#8221;.<br />
<span style="text-align:center; display: block;"><a href="http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/"><img src="http://img.youtube.com/vi/6pXMd7PW1wY/2.jpg" alt="" /></a></span><br />
<strong>My Thoughts:</strong> Except for <a href="http://fusoya.eludevisibility.org/soe/patch.html">a certain two player modification</a>, this has got to be my favorite ROM hack. The reason&#8217;s simple: it&#8217;s the only one that&#8217;s well designed! Level design on most hacks is idiotic; the goal seems to be to get the player lost, confused, and frustrated. Let&#8217;s not forget that one of the most fun parts of the original SMW was improving to the point where you could run through the early levels with ease. Super Mario World Odyssey is a nice mix of challenging, fun, and epic grandness. It&#8217;s a shame that the developer hasn&#8217;t spoken up in years; this is one of the few hacks I&#8217;m actually looking forward to.</p>
<p><strong><em>The Legend Of Zelda: Lost Isle</em></strong><br />
<strong>Summary:</strong> Technically not a hack. Based off a Zelda engine that was first reverse-engineered and then enhanced. Very thorough, very pretty.<br />
<span style="text-align:center; display: block;"><a href="http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/"><img src="http://img.youtube.com/vi/nHLBCQigbAU/2.jpg" alt="" /></a></span><br />
<strong>My Thoughts:</strong> Apologies if I appear nonplussed, but I find even the copyright holders <a href="http://en.wikipedia.org/wiki/The_Adventure_of_Link">mess</a> <a href="http://en.wikipedia.org/wiki/The_Legend_of_Zelda:_Oracle_of_Seasons_and_Oracle_of_Ages">up</a> Zelda <a href="http://en.wikipedia.org/wiki/The_Legend_of_Zelda:_The_Minish_Cap">quite</a> <a href="http://en.wikipedia.org/wiki/CD-i_games_from_The_Legend_of_Zelda_series">often</a> -so how can hobbyists hope to get it right? The dungeons in this game are needlessly confusing, and the overworld is basically dead. That said, compared to <a href="http://zeldaparallelworlds.googlepages.com/">Parallel Worlds</a>, this game is not bad. Sure, it&#8217;s got a huge world map, but it also implemented a useful teleport system to ease the burden of long treks through the jungle. And the world really retains the &#8220;feel&#8221; of the Zelda universe, which is clearly a credit to the designer&#8217;s skill. No offense intended to the Parallel Worlds team, by the way; <em>that</em> hack is vast and professional, but its general design is uninspiring and amateurish. Consider it constructive criticism: the game would be an excellent first draft, in the sense that seriously re-tooling half of it would do wonders.</p>
<p><strong><em>SMW Zelda (Un-Named Hack)</em></strong><br />
<strong>Summary:</strong> For completeness, this hack combines the previous two games! It&#8217;s a 2-D, Mario-ish Zelda game!<br />
<span style="text-align:center; display: block;"><a href="http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/"><img src="http://img.youtube.com/vi/mCG1MrtAfAg/2.jpg" alt="" /></a></span></p>
<p><strong><span style="color:#ff0000;">Important Note</span>: </strong>For some reason, all links to the SMW Zelda hacks (indeed, all links to the author&#8217;s work, including his SMW Metroid hacks) have been removed from Youtube. I&#8217;m not sure what happened&#8230;. and if anyone has a copy, could you please send me a link? Until then, I&#8217;ve linked to a video of an &#8220;auto&#8221; Super Mario World level. I&#8217;ve always liked the auto levels; they showcase some really random happenstance, but are obviously planned for by the developer. I particularly like horizontal auto levels, as it&#8217;s much harder to make than a simple vertical drop.</p>
<p><strong>My Thoughts:</strong> I&#8217;m cautiously optimistic about this one. I&#8217;ve always wondered what a 2-D Zelda game would be like, but I always thought it&#8217;d be more like <a href="http://www.neopets.com/games/play.phtml?game_id=349">Hannah and the Pirate Caves</a>. Still, I like the hacker&#8217;s take on this one. The Deku Leaf is not just a weakly disguised cape; Deku Nuts (not shown) go straight forward but bounce at an angle, and the shield repels enemies. I found <a href="http://kotaku.com/5139756/">Legend of Princess</a> to be a disappointing attempt at a 2-D Zelda (except fighting Shadow Princess; that was <strong>amazing</strong>), but so far, &#8220;SMW Zelda&#8221; seems like it&#8217;s blending both games to come up with something new. I really, really hope this one turns out good.</p>
<p><strong><em>Super Mario World: The Second Reality Project 1</em></strong><br />
<strong>Summary:</strong> An &#8220;old-school&#8221; Mario World hack, which means the Overworld and the blockset haven&#8217;t been modified; only the levels have been changed.<br />
<span style="text-align:center; display: block;"><a href="http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/"><img src="http://img.youtube.com/vi/MJ1TqXxH2Xw/2.jpg" alt="" /></a></span><br />
<strong>My Thoughts:</strong> I dislike most Mario hacks. <a href="http://video.google.com/videoplay?docid=2587443048356325606">Super Demo World</a> was nice to look at and modestly creative, but it gave me headaches. Various other hacks, requiring you to pull off such stunts as spin-jumping while holding a P-switch, were mere tributes to their designers&#8217; egos. However, SRP1 offers something none of those do: an &#8220;easy mode&#8221; which is actually playable without savestates. It&#8217;s incredibly challenging, but so far (World 6) I wouldn&#8217;t say it&#8217;s unfair. (<strong>Editor&#8217;s note: </strong>Worlds 7+ are unfair.) And because it doesn&#8217;t use nonstandard hacks, <a href="http://www.snemul.com/ds/">I can take it on the go</a>. If all developers took the time to step back and actually try their game out as a player instead of a developer or hobbyist, I think we&#8217;d have a lot more easy mode hacks, and homebrew would be all the better for it.</p>
<p><strong><em>Various Spriter Sonikku Tricks (not a hack)</em></strong><br />
<strong>Summary:</strong> Some fascinating (but simple) ideas from a hacker.<br />
<span style="text-align:center; display: block;"><a href="http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/"><img src="http://img.youtube.com/vi/TaPsNcHS8hg/2.jpg" alt="" /></a></span><br />
<strong>My Thoughts:</strong> As a bit of a parting shot, have a look at this guy&#8217;s hack videos. It seems like he strives for simple, elegant hacks with lots of stopping power. Consider the video above, which allows bombs to destroy an on/off switch. I can immediately think of two clever tricks (and one gimmick) leveraging this ability. Although I don&#8217;t particularly like his games, Spriter Sonikku&#8217;s approach to development is geared towards maximum effect. Excellent~</p>
<p><em><strong>Further Work</strong></em><br />
The Second Reality Project: Reloaded is a re-write of TSRP1 which changes very little in the way of level design and adds a much more coherent backstory.<br />
<span style="text-align:center; display: block;"><a href="http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/"><img src="http://img.youtube.com/vi/Ytl0TeihTV0/2.jpg" alt="" /></a></span><br />
I have a theory that good designers, when constrained, can sometimes produce better work than when they have full freedom. The Reloaded hack, for example, encouraged FPI productions to reuse older levels and eschew most custom blocks and scripts. In the end, I found this game better than both TSRP1 <em>and</em> TSRP2. So, in the spirit of being creative under extreme pressure, here&#8217;s your assignment for this week:</p>
<ul>
<li>Take a hack you enjoy somewhat, and pretend that your friend has asked you to spruce this up for a 1.1 release. Design (on paper; no code necessary) an improved hack which modifies very little from the original game but feels much more consistent overall. Try to write a few sentences describing the overall feel of the game, and then pinpoint parts of it that clash with this. Make sure you only suggest improvements which you know are possible. Try to limit yourself; pretend that you have a few friends to help you (for time-consuming tasks like replacing graphics), but you only have 6 months to develop the new version.</li>
</ul>
<p>Design documents are due on my desk by Monday, although to quote a random internet source, I will also accept the excuse &#8220;I&#8217;m too lazy to do it&#8221;.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/81/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=81&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2009/06/01/rev-1-current-exciting-hacks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>
	</item>
		<item>
		<title>[EL-1] Game Event Notifier</title>
		<link>http://lthzelda.wordpress.com/2009/04/11/el-1-game-event-notifier/</link>
		<comments>http://lthzelda.wordpress.com/2009/04/11/el-1-game-event-notifier/#comments</comments>
		<pubDate>Sat, 11 Apr 2009 13:20:09 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=64</guid>
		<description><![CDATA[Blog Info: I’ve made a habit of switching topics often on this blog. This might frustrate some of my readers, but believe me, it’s much healthier than constantly revising one project over and over. Besides, since none of these projects &#8230; <a href="http://lthzelda.wordpress.com/2009/04/11/el-1-game-event-notifier/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=64&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em><strong>Blog Info:</strong> I’ve made a habit of switching topics often on this blog. This might frustrate some of my readers, but believe me, it’s much healthier than constantly revising one project over and over. Besides, since none of these projects are real money-makers, we might as well build as broad a tool-set as possible. So in this guide, we’ll learn a bit about Win32, one of the oldest stable windowing toolkits in existence. </em></p>
<p><strong><em>Back-story:</em></strong> Everyone has their MMO of choice. I play <a href="http://www.eternal-lands.com/page/images/screenshots/sedicolis.jpg">Eternal Lands</a> because it&#8217;s very, <em>very</em> slow-paced, so I have no chance of getting hooked on it. It&#8217;s also quite balanced, and has beautiful scenery and a believable set of systems. You could really tell a story using that world. That said, some minor in-game features really bother me. For example, when you are gathering (“harvesting”) vegetables and minerals, you often unearth some nasty surprise that causes your character to pause. Since harvesting is meant to be the kind of thing you minimize the game for, this means that you’ll be constantly bringing the game back just to check if you’ve been interrupted.</p>
<p><strong>Goal:</strong> Figure out a way to notify players when they stop harvesting. Perhaps a pop-up notification like Google Talk provides?</p>
<p><em>A note about Linux:</em> Despite the fact that <em>Eternal Lands</em> is actually <strong><em>easier </em></strong>to compile under Linux, I’ll be developing this plugin under Windows. GTK fans should have enough knowledge to be able to port this example to Linux. My reason for doing this is simple: on my machine, <em>Eternal Lands</em> runs better on Windows. I’m all for equality, but I’m not going to handicap myself for the sake of fairness.</p>
<p><strong>Getting the Source</strong><br />
<em>Eternal Lands</em> is rather unique in that the client is open-source. I find this rather trusting of the developers, although presumably they did it so that they could get features patched in by the user community. This makes our project a <em>lot </em>easier, so let’s grab the source right away. You’ll need <a href="http://www.tortoisecvs.org/download.shtml">Tortoise CVS</a>. (Note that Tortoise CVS works fine on Windows Vista, as long as you don’t try to perform a <strong>CVS Checkout</strong> in a protected directory like C:\windows.) The source is located at the project’s <a href="http://developer.berlios.de/cvs/?group_id=1256">BerliOS repository</a>. To access it, create a folder called “EL Client” somewhere on your system. Open the folder, right-click, and choose “CVS Checkout…”. Copy and paste the <strong>CVS Root</strong> from the source page into the corresponding checkout field; it’ll look something like this:<br />
<code style="color:black;">:pserver:anonymous@cvs.elc.berlios.de:/cvsroot/elc</code><br />
Then, enter <strong>elc </strong>for the module name. You can now click Ok:</p>
<div id="attachment_67" class="wp-caption alignnone" style="width: 267px"><em><strong><a href="http://lthzelda.files.wordpress.com/2009/04/post5_cvs_checkout.png"><img class="size-medium wp-image-67" title="post5_cvs_checkout" src="http://lthzelda.files.wordpress.com/2009/04/post5_cvs_checkout.png?w=257&#038;h=187" alt="Entering the CVS Root and the Module Name enables the &quot;Ok&quot; button." width="257" height="187" /></a></strong></em><p class="wp-caption-text">Entering the CVS Root and the Module Name enables the &quot;Ok&quot; button.</p></div>
<p>The entire project contains lots of files, so you’ll have to wait a while for them all to download. While you’re at it, make sure you’ve downloaded and installed the Windows client of <em>Eternal Lands</em> <a href="http://www.eternal-lands.com/page/download.php">from the main site</a>. (You might consider the <a href="https://addons.mozilla.org/en-US/firefox/addon/201">Down Them All</a> plugin for Firefox, as the <em>Eternal Lands</em> site will occasionally yahtzee your connection.) This will make running the .exe you compile much easier.</p>
<p><strong>Theory, Approach, and Not Getting Banned</strong><br />
While our downloads chug along their merry way, let’s talk design. First of all, what’s our end goal? That’s easy: “When the client shows the message <strong>You have stopped harvesting</strong> we should show a popup near the system tray if the <em>Eternal Lands</em> client is minimized.”</p>
<p>Next question: is this legal? Modification of the client code is fine, since the license is very liberal about the source. Actually using it to connect to the game requires that we subscribe to the terms and conditions of <em>Eternal Lands</em>. The only one that applies to us is:</p>
<p><code style="color:black;">[No] macroing, automating, scripting, exploiting bugs...</code></p>
<p>However, I don’t think we’re in violation of this. We&#8217;re not macroing, and the only thing we are automating or scripting is the use of Alt+Tab. I don’t think <a href="http://eternal-lands.blogspot.com/">Entropy </a>would insist that we constantly check up on our harvesting progress, especially since shell scripts in Linux to check the message logs have been received no hostility on the forums. In fact, this notification actually maximizes the ratio of player-controlled time to time wasted standing still.</p>
<p>Well, it’s nice that we won’t get banned for doing this, but how will we actually <em>program </em>it? There are two approaches I can see: either modify the game to display the window itself, or create a separate program that intercepts packets sent to <em>Eternal Lands</em> and determines if any of these packets represent the <strong>You have stopped harvesting</strong> message. There are pros and cons to each approach:</p>
<p><em>Modifying the Game Client</em><br />
<span style="color:green;"><strong>Pros </strong></span></p>
<ul style="list-style-type:square;">
<li>You won’t lose any speed. Checking each message and responding only for a few specific ones will not affect performance.</li>
<li>Modifying the code itself is easy; you won’t have to play with firewalls or packet interceptors.</li>
</ul>
<p><span style="color:red;"><strong>Cons </strong></span></p>
<ul style="list-style-type:square;">
<li>You’ll have to be able to compile the client. For some games (especially cross-platform ones like Eternal Lands) this can be a show-stopper; it’s difficult!</li>
<li>You’ll need to re-apply your fix every time a new game client is released. This should be easy, but major releases (especially ones that use new libraries) might bring up the issue of compiling again.</li>
</ul>
<p><em>Intercepting Packets</em><br />
<span style="color:green;"><strong>Pros </strong></span></p>
<ul style="list-style-type:square;">
<li>No modification to the client is necessary. You can easily start the client with or without this feature enabled.</li>
<li>When a new client is released, your code might continue to work! In fact, it will only fail if the connection protocol or information protocol changes, which is something the developers will probably avoid.</li>
<li>You can develop in your favorite IDE; you don’t have to compile their code first. Consider: let’s say that we’re running a Windows game in Wine; compiling the client could be a nightmare!</li>
<li>The result is slightly easier to port than modifying the code.</li>
</ul>
<p><span style="color:red;"><strong>Cons </strong></span></p>
<ul style="list-style-type:square;">
<li>The concept is more difficult; we’re dealing with packet nonsense instead of strings.</li>
<li>If your code isn&#8217;t fast, it might cause your game to lag, since you&#8217;re dealing with all packets, not just the rare console message.</li>
</ul>
<p>Since this is our first tutorial on <em>Eternal Lands</em>, we’ll modify the client code directly. In our next lesson, we’ll create a packet interception program, and polish up the interface so it looks real shiny-like.</p>
<p><strong>Compiling the Code</strong><br />
The <strong>Official Eternal Lands Client Development Site</strong> has <a href="http://www.eternal-lands.com/forum/index.php?showtopic=35624">instructions for compiling the client using Dev C++</a>. I followed these instructions and they worked perfectly. If this link is ever broken, you’ll have to figure it out on your own, or you can try compiling the client on Linux and re-working this tutorial from there.</p>
<p>You might want to remove debugging symbols from the compiled executable; this makes it about 77% smaller. To do that, add the line <code style="color:black;">strip –s $(EXE)</code> to the end of your $(EXE) target. In other words, in Makefile.win, find the following:<br />
<code style="color:black;">$(EXE): main.o $(TMP_LIB)<br />
$(LINK) $(CFLAGS) $&lt; -L. -lelc $(LDFLAGS) -o $(EXE)</code><br />
..and replace it with:<br />
<code style="color:black;">$(EXE): main.o $(TMP_LIB)<br />
$(LINK) $(CFLAGS) $&lt; -L. -lelc $(LDFLAGS) -o $(EXE)<br />
strip -s $(EXE)</code><br />
Although the original 11.1MB isn’t too big, the resultant 2.56 MB is small enough to email to a friend.</p>
<p>To run the program, you should follow their instructions for running a local copy. In particular:</p>
<li>Copy the contents of the “Eternal Lands” directory from the official client release (e.g., C:\Program Files\Eternal Ladns) to a new directory called “Release” in the “EL Client” directory where you saved the source.</li>
<li>After you correctly compile the source in Dev C++, you’ll have a file el.exe in the “EL Client” directory. Copy that into the “Release” directory, over-writing the file that’s there.</li>
<li>Copy the files libcal3d-12.dll and alut.dll from <code style="color:black;">C:\Dev-Cpp\dll</code> and <code style="color:black;">C:\Dev-Cpp\lib</code> (respectively) to Release, over-writing the files there.</li>
<li>Run el.exe in the “Release” directory.</li>
<p>Wow! I don’t know about you, but for me, simply re-compiling the client caused it to run about <strong>30% faster</strong>! This is particularly astounding, since I wouldn’t expect a naïve build to optimize better than the developer’s build. Someone should try compiling this thing in Visual Studio with <a href="http://msdn.microsoft.com/en-us/library/aa289170.aspx">PGO </a>and seeing if we can make it even faster.</p>
<div id="attachment_66" class="wp-caption alignnone" style="width: 214px"><a href="http://lthzelda.files.wordpress.com/2009/04/post5_client_compiles_ok.png"><img class="size-medium wp-image-66" title="post5_client_compiles_ok" src="http://lthzelda.files.wordpress.com/2009/04/post5_client_compiles_ok.png?w=204&#038;h=152" alt="Our Client Compiles, And It Looks Great!" width="204" height="152" /></a><p class="wp-caption-text">Our Client Compiles, And It Looks Great!</p></div>
<p><strong>Adding a Window at Startup</strong><br />
The next logical step is to create a simple window as a proof-of-concept, and show it when Eternal Lands starts up. We’ll be using pure Win32 C to code this.<br />
In Dev C++, click “File-&gt;New-&gt;Source File” and choose “Yes” when asked if you want to add this file to the current project. Then, immediately “save” the file as <strong>taskbaralerts.h</strong>, with a type of “Header Files”. Do the same for another file, <strong>taskbaralerts.c</strong>, of type “C source file”. These will contain the bulk of our implementation; it’s a very good idea to keep as much code as possible <em>out </em>of the official EL source files.</p>
<p>Enter the following into taskbaralerts.h:<br />
<code style="color:black;"><span style="color:#000066;">#ifndef TASKBARALERTS_H<br />
#define TASKBARALERTS_H</span></code></p>
<p><span style="color:green;">//Includes</span><br />
<span style="color:#000066;">#include &lt;stdio.h&gt;<br />
#include &lt;windows.h&gt;</span></p>
<p><span style="color:green;">//Function prototypes</span><br />
LRESULT CALLBACK AlertsWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);<br />
void initAlertsWindow(HINSTANCE hInst, char *windowClassName);</p>
<p><span style="color:#000066;">#endif</span> <span style="color:green;">//TASKBARALERTS_H</span></p>
<p>The #ifndef/#define/#endif triplet is known as an <a href="http://en.wikipedia.org/wiki/Include_guard">Include Guard</a>, and it prevents us from defining multiple versions of “initAlertsWindow”. Now, any file that wants to use these functions can simply include <strong>taskbaralerts.h</strong> and everything will run smoothly.</p>
<p>Of course, we need to actually implement these somewhere. Add this to taskbaralerts.c:</p>
<p><code style="color:black;"><span style="color:#000066;">#include "taskbaralerts.h"</span></code></p>
<p><span style="color:green;">//Global variable</span><br />
HWND alertsWindow = NULL;<br />
HWND hStatic = NULL;<br />
BOOL windowVisible = FALSE;<br />
HINSTANCE myHInst = NULL;<br />
HBRUSH bkgrdBrush = NULL;</p>
<p><span style="color:green;">//Message-handling callback</span><br />
LRESULT CALLBACK AlertsWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)<br />
{<br />
switch(msg)<br />
{<br />
case WM_CREATE:<br />
{<br />
hStatic = CreateWindowEx(WS_EX_LEFT, &#8220;Static&#8221;, &#8220;&#8221;,<br />
WS_CHILD | WS_VISIBLE,<br />
5, 10, 180, 50,<br />
hwnd, NULL, myHInst, NULL);<br />
SetWindowText(hStatic, &#8220;EL Notification Area&#8221;);<br />
break;<br />
}<br />
case WM_LBUTTONDOWN:<br />
{<br />
<span style="color:green;">//Hide our window</span><br />
windowVisible = FALSE;<br />
ShowWindow(hwnd, SW_HIDE);<br />
break;<br />
}<br />
case WM_CLOSE:<br />
{<br />
<span style="color:green;">//Over-ride: Hide our window</span><br />
windowVisible = FALSE;<br />
ShowWindow(hwnd, SW_HIDE);<br />
break;<br />
}<br />
case WM_DESTROY:<br />
{<br />
<span style="color:green;">//Close the window for good.</span><br />
PostQuitMessage(0);<br />
break;<br />
}<br />
default:<br />
return DefWindowProc(hwnd, msg, wParam, lParam);<br />
}<br />
return 0;<br />
}</p>
<p>void initAlertsWindow(HINSTANCE hInst, char *windowClassName)<br />
{<br />
<span style="color:green;">//Declare c-style variables</span><br />
RECT r;<br />
WNDCLASSEX wc;</p>
<p><span style="color:green;">//Save</span><br />
myHInst = hInst;</p>
<p><span style="color:green;">//Necessary?</span><br />
if (alertsWindow!=NULL) {<br />
return;<br />
}</p>
<p><span style="color:green;">//Make a brush</span><br />
bkgrdBrush = CreateSolidBrush(RGB(0, 0, 0));</p>
<p><span style="color:green;">//Set a window class&#8217;s parameters</span><br />
wc.cbSize = sizeof(WNDCLASSEX);<br />
wc.style = 0;<br />
wc.lpfnWndProc = AlertsWndProc;<br />
wc.cbClsExtra = 0;<br />
wc.cbWndExtra = 0;<br />
wc.hInstance = hInst;<br />
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);<br />
wc.hCursor = LoadCursor(NULL, IDC_ARROW);<br />
wc.hbrBackground = bkgrdBrush;<br />
wc.lpszMenuName = NULL;<br />
wc.lpszClassName = windowClassName;<br />
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);<br />
if(!RegisterClassEx(&amp;wc)) {<br />
alertsWindow = NULL;<br />
return;<br />
}</p>
<p><span style="color:green;">//Get the desktop</span><br />
GetWindowRect(GetDesktopWindow(), &amp;r);</p>
<p><span style="color:green;">//Create a handle to the window</span><br />
alertsWindow = CreateWindowEx(<br />
WS_EX_TOPMOST | WS_EX_NOACTIVATE,<br />
windowClassName,<br />
&#8220;Eternal Lands Notification&#8221;,<br />
WS_CAPTION | WS_SYSMENU, //Simple<br />
r.right-200, r.bottom-100, 200, 100,<br />
NULL, NULL, hInst, NULL<br />
);<br />
if (alertsWindow==NULL) {<br />
return;<br />
}</p>
<p><span style="color:green;">//TEMP: Show the window</span><br />
windowVisible = TRUE;<br />
ShowWindow(alertsWindow, SW_SHOW);<br />
UpdateWindow(alertsWindow);<br />
<span style="color:green;">//TEMP end</span><br />
}</p>
<p>That’s a lot to digest. Let’s start at <strong>initAlertsWindow()</strong>, which the main game should call when it first loads. First, we check if <strong>alertsWindow</strong> is not NULL, which could happen if, say, the game restarts itself by re-running <strong>main()</strong>. Next, we fill out the parameters of our <a href="http://msdn.microsoft.com/en-us/library/ms633577%28VS.85%29.aspx">WNDCLASSEX</a> struct. (The MSDN has very good documentation (except, occasionally, when it’s <strong><em>totally wrong!</em></strong>) on its Win32 API, so I’ll be linking to that quite a bit.) The parameter of interest is <strong>lpfnWndProc</strong>, which points to the function which handles messages for this window. We set it to <strong>AlertsWndProc</strong>. This means that every time a message is dispatched to our alerts window, the <strong>AlertsWndProc </strong>function handles it.</p>
<p>Now, we try to register this window class. The function call might fail if, say, <em>Eternal Lands</em> has already created a window class with this name. At any stage along the way, if a function call fails, we simply return. Now we are ready to create the window.  However, since we want to position it on the lower-right corner of the screen, we’ll need to know how big the desktop is. So, we call <strong>GetWindowRect(GetDesktopWindow(), &amp;r)</strong>, which stores the desktop’s dimensions in <strong>r</strong>. Now, we can call <a href="http://msdn.microsoft.com/en-us/library/ms632680(VS.85).aspx">CreateWindowEx</a>. Parameters of interest include:</p>
<ul>
<li>The <strong>dwExStyle </strong>is used to describe what type of window we want. <strong>WS_EX_TOPMOST</strong> means that we want our window to appear above all other non-topmost windows, and <strong>WS_EX_NOACTIVATE</strong> means that we want our new window to show, but not to take keyboard focus or have a section on the taskbar. This makes sense; if we are typing in Microsoft Word when we stop harvesting, we want the notification to appear above Word, but we don’t want it to take the focus away from word.</li>
<li>The <strong>dwStyle </strong>parameter describes what our window looks like. We give it a <strong>WS_CAPTION</strong>, and add a <strong>WS_SYSMENU</strong> so that the user can “close” the window if he wants to. Nothing fancy here.</li>
<li>The four paraemeters <strong>x</strong>, <strong>y</strong>, <strong>nWidth</strong>, and <strong>nHeight </strong>position our window on the lower-right corner of the screen. You can fiddle with it if you want to display it above the taskbar; it doesn’t really bother me.</li>
</ul>
<p>That’s all there is to creating the window, and showing it is easy enough. The <strong>AlertsWndProc </strong>function simply switches through the variety of message types we can receive, returning “0” if it sees nothing of interest (which tells Windows to handle the message itself). In the <strong>WM_CREATE</strong> message, we add a static sub-window (called a “Label” in other languages) so that we can potentially display multiple messages in the future. The <strong>WM_LBUTTONDOWN</strong> message tells our window to hide itself; this lets the user simply click on the notification window to make it go away. We also intercept the <strong>WM_CLOSE</strong> message, because we don’t want the “X” button to actually close the window. <strong>WM_DESTROY</strong> functions normally for destroying a window, since closing <em>Eternal Lands</em> will also close all of its windows. (Don’t worry, this code won’t spawn any hidden processes that you’ll have to Ctrl+Alt+Delete).</p>
<p>There’s a few things left to do before we actually run this:</p>
<ol>
<li>In Makefile.win, find the line that begins with <strong>COBJS=</strong> and add <strong>taskbaralerts.o</strong> in between <strong>tabs.o</strong> and <strong>text.o</strong>. If you were paying attention you’d notice that although we include taskbaralerts.h in several places, nothing links to taskbaralerts.c! This addition ensures that the linker can find your functions.</li>
<li>In main.c, add <strong>#include &#8220;taskbaralerts.h&#8221;</strong> at the top of the file. If you want, you can add an #ifdef check so that the client will still compile under Linux, but it’s not really necessary. Now, find the line <strong>init_stuff();</strong> and add <strong>initAlertsWindow(hInst, &#8220;EL_Taskalert&#8221;);</strong> after it. This will initialize our taskbar alert code right before Eternal Lands starts rendering the main game.</li>
<li>Unfortunately, hInst isn’t defined. Find the line <strong>char   *win_command_line;</strong> at the top of the file, and add <strong>HINSTANCE hInst;</strong> after it. Then, find the function <strong>APIENTRY WinMain</strong> and add <strong>hInst = hInstance;</strong> after <strong>int argc;</strong> —that was easy, right?</li>
</ol>
<p>So, shall we run this code? Compile it, and copy <strong>el.exe</strong> into the Release directory. Run it, and you’ll see our window pop up about halfway through the boot sequence. If you’re in full-screen mode, this will be very obvious.</p>
<div id="attachment_69" class="wp-caption alignnone" style="width: 225px"><a href="http://lthzelda.files.wordpress.com/2009/04/post5_window_pops_up.png"><img class="size-medium wp-image-69" title="post5_window_pops_up" src="http://lthzelda.files.wordpress.com/2009/04/post5_window_pops_up.png?w=215&#038;h=89" alt="Our Notification Is Created When EL Starts" width="215" height="89" /></a><p class="wp-caption-text">Our Notification Is Created When EL Starts</p></div>
<p><strong>Intercepting Messages</strong><br />
Delete the lines we wrapped with the <strong>“TEMP…TEMP end” </strong>comments so that our window won’t show. It’s time to start fiddling with EL’s messages. In Dev C++ click “Search-&gt;Find In Files”. This allows us to search every file in our project for some text, and is indispensable when programming in C. Let’s try to find a message —any message— and go from there. What’s the most unique word in Eternal Lands? How about “radon”? Type it in and click “Ok”. The highlighted result looks particularly promising; double-click and you’ll be brought to the code that contains this —yep, it’s a big array of message strings:</p>
<div id="attachment_68" class="wp-caption alignnone" style="width: 256px"><a href="http://lthzelda.files.wordpress.com/2009/04/post5_search_for_radon.png"><img class="size-medium wp-image-68" title="post5_search_for_radon" src="http://lthzelda.files.wordpress.com/2009/04/post5_search_for_radon.png?w=246&#038;h=220" alt="We've Found The Radon Message (It's Misspelled As &quot;Radeon&quot; In One Location)" width="246" height="220" /></a><p class="wp-caption-text">We&#39;ve Found The Radon Message (It&#39;s Misspelled As &quot;Radeon&quot; In One Location)</p></div>
<p>The name of the array is <strong>temp_event_string</strong>; scan the file a bit and you’ll find that this gets sprintf’d into <strong>search_str</strong>, replacing the <strong>%s</strong> with <strong>username_str</strong>. Well… that’s a tangential bit of useful information. Do a “Find In Files…” on <strong>username_str</strong> and you’ll see that it’s defined in <strong>interface.h</strong>. So, if we include <strong>interface.h</strong>, we can access our player’s name. Getting back to the problem at hand, do a “Find in Files…” on <strong>catch_counters_text </strong>(the name of the function which accesses <strong>search_str</strong>), and you’ll see that <strong>text.c</strong> calls this in <strong>filter_or_ignore_text()</strong>. We just completed a bottom-up search; if you did a top-down search starting from the TCP layer, you’d end up at the same place. Go to the top of the function, under <strong>#endif // NEW_SOUND</strong>, and put in a call to <strong>check_taskbar_alerts(text_to_add);</strong> —making sure to <strong>#include &#8220;taskbaralerts.h&#8221;</strong> somewhere at the top of the file. Now, switch back to <strong>taskbaralerts.h</strong> and add a function prototype:<br />
<code style="color:black;">void check_taskbar_alerts(char * text);</code><br />
In <strong>taskbaralerts.c</strong>, add <strong>#include &#8220;interface.h&#8221;</strong> at the top of the file so we can access our player’s name. Now, before we go any further, we have a small problem. You see, the mess you receive isn’t exactly equal to &#8220;You stopped harvesting.&#8221; There’s a character at the beginning which specifies the color of the string. We could simply <strong>strcmp </strong>on &#8220;\x7FYou stopped harvesting.&#8221;, but this breaks our code if the color of this message changes. What we want is a function named “stringcontains”, which we’ll write next. (Of course, if a player now PMs you with the message <strong>You stopped harvesting</strong>, this will also set off your alarm. However, I think it’s better to react to this case then try to prevent it.) Add the following code at the top of taskbaralerts.c:</p>
<p><code style="color:black;">BOOL strcontains(char* src, char* pattern)<br />
{<br />
<span style="color:green;">//Init some tracking variables</span><br />
int i;<br />
int len;<br />
int patIndex = 0;<br />
int patLen;</code></p>
<p><span style="color:green;">//Loop</span><br />
len = strlen(src);<br />
patLen = strlen(pattern);<br />
for (i=0; i&lt;len; i++) {<br />
<span style="color:green;">//Have we reached a non-match?</span><br />
if (src[i]!=pattern[patIndex]) {<br />
patIndex = 0;<br />
}</p>
<p><span style="color:green;">//Continue tracking our pattern</span><br />
if (src[i]==pattern[patIndex]) {<br />
if (patIndex==patLen-1) {<br />
return TRUE;<br />
} else {<br />
patIndex++;<br />
}<br />
}<br />
}<br />
return FALSE;<br />
}</p>
<p>This function is simple enough; whenever it matches the first letter of the pattern with the current index in the string, it simply assumes it has a match, and resets to zero if that assumption is broken. This will fail if you’re looking for ABAC in the string ABABAC, so you can re-write it later (when we test for usernames) if your username is something funky like that.</p>
<p>Now, let’s hook this function up:</p>
<p><code style="color:black;"><span style="color:green;">//Bring up our window?</span><br />
void check_taskbar_alerts(char * text)<br />
{<br />
<span style="color:green;">//Can we track this at all?</span><br />
if (alertsWindow==NULL) {<br />
return;<br />
} else if (windowVisible==TRUE) {<br />
windowVisible = FALSE;<br />
ShowWindow(alertsWindow, SW_HIDE);<br />
}</code></p>
<p><span style="color:green;">//Have we stopped harvesting?</span><br />
if (strcontains(text, &#8220;You stopped harvesting&#8221;)==TRUE) {<br />
<span style="color:green;">//Prompt the user</span><br />
SetWindowText(hStatic, &#8220;You stopped harvesting.&#8221;);<br />
windowVisible = TRUE;<br />
ShowWindow(alertsWindow, SW_SHOW);<br />
UpdateWindow(alertsWindow);<br />
}<br />
}</p>
<p>Again, simplicity rules the day. This function checks each message as it is received. If the <strong>alertsWindow </strong>is still visible, that means the user forgot to close it, and we do that for them. Since users are prompted when they begin harvesting, this ensures that the window won’t give any false positives. We then use our new <strong>strcontains()</strong> method to check if our message looks something like “You stopped harvesting”. If so, we change the text of the window and make it visible. Compile the project and run it. It works! —but there’s one obvious flaw.</p>
<p><strong>Only Displaying the Notification if We’re Not Viewing <em>Eternal Lands</em></strong><br />
That’s right —the notification appears whenever we stop harvesting, even if we’re currently watching the <em>Eternal Lands</em> window. This is annoying as it grabs us out of full-screen mode. So what should we do? Well, the Eternal Lands window’s title bar contains the caption <strong>(<em>Userame </em>on main) Eternal Lands</strong>. The “main” changes if you switch servers, so let’s just use our <strong>strcontains </strong>function to search for the user’s name and the phrase Eternal Lands, and not show the window if both are present. Change our <strong>check_taskbar_alerts</strong> function to read:</p>
<p><code style="color:black;"><span style="color:green;">//Bring up our window?</span><br />
void check_taskbar_alerts(char * text)<br />
{<br />
<span style="color:green;">//Can we track this at all?</span><br />
if (alertsWindow==NULL) {<br />
return;<br />
} else if (windowVisible==TRUE) {<br />
windowVisible = FALSE;<br />
ShowWindow(alertsWindow, SW_HIDE);<br />
}</code></p>
<p><span style="color:green;">//Have we stopped harvesting?</span><br />
if (strcontains(text, &#8220;You stopped harvesting&#8221;)==TRUE) {<br />
HWND foreWnd = GetForegroundWindow();<br />
char wndTitle[200];<br />
GetWindowText(foreWnd, wndTitle, 200);</p>
<p><span style="color:green;">//Does the window title contain the user&#8217;s name and the words &#8220;Eternal Lands&#8221;?</span><br />
if ((strcontains(wndTitle, &#8220;Eternal Lands&#8221;)==TRUE) &amp;&amp; (strcontains(wndTitle, username_str)==TRUE)) {<br />
<span style="color:green;">//We&#8217;re in the game! Do nothing</span><br />
} else {<br />
<span style="color:green;">//Prompt the user</span><br />
SetWindowText(hStatic, &#8220;You stopped harvesting.&#8221;);<br />
windowVisible = TRUE;<br />
ShowWindow(alertsWindow, SW_SHOW);<br />
UpdateWindow(alertsWindow);<br />
}<br />
}<br />
}</p>
<p>Try it out, and you’ll see that everything works just fine.</p>
<p><em><strong>Possible Improvements</strong></em><br />
There’s a lot of potential for improvement, since we did such a hasty job designing our plugin. Here’s some particularly sore points; add your own and fix it up!</p>
<ul>
<li>If we stop harvesting, the message displays properly. However, it will disappear if another message occurs before we maximize the game client. Moreover, if we see the message and then open the client and tell our character to walk towards a storage (a common response to a full inventory) the message will remain until another message preempts it. Both of these glitches imply that we were wrong to assume that we should hide the alert window when a non-harvesting message appears; rather, we should hide it when the client gains focus again.</li>
<li>It would be nice to have an icon in the status bar that our window is attached to.</li>
<li>We should probably give our EL notification box a more EL-ish feel. We could do this with some simple GDI programming.</li>
<li>We should be able to track more notifications, and display nice pictures related to their content. Like… if we find gold, etc. And, we could have our system tray icon flash bright red if we die (or green if we find a rare stone!).</li>
<li>In fact, all of our suggestions are edging towards a general re-design of the plugin we made. But in that case, I’d rather not program it in pure Win32 C. If you’re of a different mind, by all means implement these changes. Me, I’ll be brushing up on .NET, Java, and Python. See you next week!</li>
</ul>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/64/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=64&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2009/04/11/el-1-game-event-notifier/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/04/post5_cvs_checkout.png?w=300" medium="image">
			<media:title type="html">post5_cvs_checkout</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/04/post5_client_compiles_ok.png?w=300" medium="image">
			<media:title type="html">post5_client_compiles_ok</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/04/post5_window_pops_up.png?w=300" medium="image">
			<media:title type="html">post5_window_pops_up</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/04/post5_search_for_radon.png?w=300" medium="image">
			<media:title type="html">post5_search_for_radon</media:title>
		</media:content>
	</item>
		<item>
		<title>[LZ-2] Bow &amp; Arrow Quest</title>
		<link>http://lthzelda.wordpress.com/2009/03/19/lz-2-bow-arrow-quest/</link>
		<comments>http://lthzelda.wordpress.com/2009/03/19/lz-2-bow-arrow-quest/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 13:03:18 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=33</guid>
		<description><![CDATA[Blog Info: These blog posts are supposed to take you about an hour to do, and me about three hours to write. That proved to be a gross underestimation –the prototype ROM for this post alone took at least three &#8230; <a href="http://lthzelda.wordpress.com/2009/03/19/lz-2-bow-arrow-quest/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=33&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em><strong>Blog Info</strong>: These blog posts are supposed to take you about an hour to do, and me about three hours to write. That proved to be a gross underestimation –the prototype ROM for this post alone took at least three hours, and writing up step-by-step instructions has taken a few hours too. But I think we really accomplish something in this post.</em></p>
<p><em><strong> Back-story</strong></em>:  We decided in the last post to modify Zelda3 to make the bow-and-arrow the primary weapon for the first part of the game. But how do we actually go about doing this? And, how can we make the first part of the castle more challenging for advanced players? An arrow-related puzzle is in order! But this means we’ll have to start learning how to use (<em><strong>shudder</strong></em>) the <em>Dungeon Editor</em>. (There is no <em>Dragon Editor</em>).</p>
<p><strong><em> Goal</em></strong>: Become proficient in using the <em>Dungeon Editor</em>, remove the sword, add the bow, and modify the first dungeon room you fall into to require the clever use of arrows to exit.</p>
<p><strong>Step 1: Understanding Backups</strong></p>
<p>Open a clean copy of Zelda3 in Hyrule Magic. Make SURE this is a <em><strong>copy</strong></em>, because I&#8217;m going to show you how simple it is to permanently muck it up. Expand “Dungeons” and click “Starting Location 03”, then click on the “More” button at the bottom of the dungeon screen (near “Starting Location”). See the radio button for “Upper Left”, next to “Horizontal Scroll”? Click that:</p>
<div id="attachment_43" class="wp-caption alignnone" style="width: 220px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_mess_up.png"><img class="size-medium wp-image-43" title="post4_mess_up" src="http://lthzelda.files.wordpress.com/2009/03/post4_mess_up.png?w=210&#038;h=151" alt="Clicking This Radio Button Will Definitely Crash Zelda3." width="210" height="151" /></a><p class="wp-caption-text">Clicking This Radio Button Will Definitely Crash Zelda3.</p></div>
<p>&#8230;and then click “Ok” and save. Start the ROM&#8230;. and notice that it crashes after the name select screen. Ok, go back to the “More” button and change the setting back to “Upper Right”. Save, start the ROM&#8230;. it&#8217;s <em>still </em>failing to work.</p>
<p>With one simple click, we have irreversibly corrupted our ROM. Sure, you can try to HEX it back to the <em>status quo</em>, but that could take hours. A better solution is to keep regular backups, and to do your most dangerous fiddling directly <em>after </em>you backup. Really, I&#8217;m not kidding when I say that you <em>need </em>to back up your working ROM far more often than usual.</p>
<p><strong>Step 2: Understanding the Dungeon Editor</strong></p>
<p>Open a clean copy of the Zelda3 ROM in Hyrule Magic. It&#8217;s time to play around with the dungeon editor. Open an MP3 player, too, for your sanity.</p>
<p>Expand the “Dungeons” tab and browse down to “Starting Location 04”. Double-click, and you should see a familiar room: the entrance to the sewers. In the top-left corner of the window it says “Room 81”. Next to this are some arrows to switch to the next room in each of the four directions. Finally, there is a “Jump” button which allows you to go immediately to a room by number. Click on the arrows a few times to see where it takes you, and then click on “Jump”, type in “81” and hit “Ok”. You&#8217;re now back at the throne room.</p>
<div id="attachment_42" class="wp-caption alignnone" style="width: 195px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_jump_to_room.png"><img class="size-medium wp-image-42" title="post4_jump_to_room" src="http://lthzelda.files.wordpress.com/2009/03/post4_jump_to_room.png?w=185&#038;h=143" alt="The Jump to Room Box" width="185" height="143" /></a><p class="wp-caption-text">The Jump to Room Box</p></div>
<p>Close the dungeon view and scroll down to “Entrance 32” &amp; open it. This is the room you fall into after pulling up that bush outside the castle. Actually, that&#8217;s somewhat inaccurate. This <em><strong>entrance </strong></em>only takes effect when you walk out of and then back into this room. It is the same <strong>room </strong>as the one you fall into (and the one you start from after saving) but depending on how you enter the room determines a number of minor things like where the camera starts. It&#8217;s important to remember this when you edit certain properties of this entrance. Make sure you <em><strong>always </strong></em>access it by double-clicking “Entrance 32”, unless I tell you to click “Starting Location 03”.</p>
<p>Look at the box in the lower-right corner of the Dungeon Window. There are several options:</p>
<ul style="list-style-type:none;">
<li><strong>“1”</strong> – Layer 1 is where we do most of our editing. Doors can go here, too. Treasure chests often are placed here.</li>
<li><strong> “2”</strong> – Layer 2 is required for some editing tricks (like bridges) –I won&#8217;t be using it here. Doors can also be placed here.</li>
<li><strong> “3”</strong> – Pretty much only doors can go here. We&#8217;ll use this layer to make an entrance leading outside –that door has to go on this layer.</li>
<li><strong> “Sprite”</strong> – Things like enemies, crystal switches, and NPCs go here.</li>
<li><strong> “Item”</strong> – Items that can be placed on the ground or in pots go here.</li>
<li><strong> “Block”</strong> – This setting lets you organize your pushable blocks. We won&#8217;t be using this.</li>
<li><strong> “Torch”</strong> – This setting is for torches. We won&#8217;t use this, except to delete one torch.</li>
</ul>
<p>Click on “1”, and then look for the corner jutting out on the left side of the watery place where you land. When you click on it, you will see the following information displayed in the lower-right:</p>
<p><code>Obj: 10D<br />
X: 2D<br />
Y: 11</code></p>
<p>Right-click on this object, and choose “Remove”. You&#8217;ve successfully deleted the corner.</p>
<div id="attachment_47" class="wp-caption alignnone" style="width: 201px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_remove_obj.png"><img class="size-medium wp-image-47" title="post4_remove_obj" src="http://lthzelda.files.wordpress.com/2009/03/post4_remove_obj.png?w=191&#038;h=146" alt="Right-Click then &quot;Remove&quot; to Delete an Object" width="191" height="146" /></a><p class="wp-caption-text">Right-Click then &quot;Remove&quot; to Delete an Object</p></div>
<p>Now click on the piece directly south of the one you deleted. Click &amp; drag it left until its X co-ordinate reads “2A”. Now move the mouse over the top edge of the same piece and click+drag to “extend” it until its “Size” reads “03”.</p>
<p>Unfortunately, the piece we moved is now <em>under </em>another piece. So, left-click on it, and then press “Ctrl+V” to bring it to the front. (Ctrl+B brings it to the back).</p>
<p>Right-click anywhere and choose “Insert an Object”. Scroll up to object 108, click it, and choose “Ok”.</p>
<div id="attachment_35" class="wp-caption alignnone" style="width: 175px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_add_new_object.png"><img class="size-medium wp-image-35" title="post4_add_new_object" src="http://lthzelda.files.wordpress.com/2009/03/post4_add_new_object.png?w=165&#038;h=126" alt="Add an Object of Type 108" width="165" height="126" /></a><p class="wp-caption-text">Add an Object of Type 108</p></div>
<p>It will appear roughly where you right-clicked; drag it to 2A,0B. Makes a nice corner, doesn&#8217;t it?</p>
<p>Congratulations, we&#8217;ve made our first real change to the room! Save.</p>
<div id="attachment_44" class="wp-caption alignnone" style="width: 210px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_move_to_front.png"><img class="size-medium wp-image-44" title="post4_move_to_front" src="http://lthzelda.files.wordpress.com/2009/03/post4_move_to_front.png?w=200&#038;h=153" alt="Move the Wall to the Front with Ctrl+V" width="200" height="153" /></a><p class="wp-caption-text">Move the Wall to the Front with Ctrl+V</p></div>
<p>We can describe what you just did using a simple table:</p>
<table style="font-family:courier;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td><strong><em>Comment</em></strong></td>
<td><strong><em>Before</em></strong></td>
<td><strong><em>After</em></strong></td>
</tr>
<tr>
<td>wall</td>
<td>x:2D y:11</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:2D y:15</td>
<td>x:2A y:0F size:3 <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:108 x:2A y:0B <em>front</em></td>
</tr>
</tbody>
</table>
<p>That means “Delete object at location 2D,11”, then “Take object at 2D,15, move it to 2A,0F, resize it to 3 units, and bring it to the front”, then “Add a new object of type 108 at 2A,0B and bring it to the front”. It&#8217;s important that you understand this syntax; we&#8217;ll be modifying a lot of objects, and it would be horribly cruel to describe each one with a paragraph.</p>
<p>The “Comment” column is an informal addition to help you keep your place.</p>
<p>A note about resizing is in order. Sometimes, when you place a piece down (particularly one that stretches vertically) the piece will stretch to fill up all available vertical space. Please note that you can <em>still </em>resize it, you just have to grab the handle at the bottom and drag it <em>all </em>the way to the top. This is annoying, but not insurmountable.</p>
<p><strong>Step3: Enabling The Bow</strong></p>
<p>Back in Entrance 32, click on the “Sprites” radio button, then click on “Priest/Uncle”. Then, right-click on him, and choose “Remove”. Our Uncle will now no longer be there to give us the sword.</p>
<p>Close Entrance 32 and open Entrance 00. Click once on the chest with the lantern. You’ll see the word “Lamp” under the “Obj” section of the window. Press “+” (or “\”) to scroll through the list of possible treasure chests until you reach “Bow” (do <em>not</em> choose “Bow&amp;Arrow” –it won&#8217;t display a message when you take it.) Then change the editing mode to “Item” and click on each heart, then using “N”, “M”, “J”, and “K” to switch the item to “Arrows”. Save.</p>
<div id="attachment_36" class="wp-caption alignnone" style="width: 196px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_change_item_to_bow.png"><img class="size-medium wp-image-36" title="post4_change_item_to_bow" src="http://lthzelda.files.wordpress.com/2009/03/post4_change_item_to_bow.png?w=186&#038;h=131" alt="You Can Change Treasure Chest Contents With + and \" width="186" height="131" /></a><p class="wp-caption-text">You Can Change Treasure Chest Contents With + and &quot;</p></div>
<p>Link now has access to the bow, 15 arrows, and not much else. Play through your game a bit, and you’ll notice that arrows are a bit hard to come by. Also, we&#8217;re stuck in the basement, due to that wall we placed in the last section. We&#8217;ll change that next.</p>
<p><strong>Step 4: A Complete Roomlet</strong></p>
<p>Modify the following in Entrance 32. Note that the “size” I specify might require you to stretch the component horizontally, vertically, or both.</p>
<table style="font-family:courier;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td><strong><em>Comment</em></strong></td>
<td><strong><em>Before</em></strong></td>
<td><strong><em>After</em></strong></td>
</tr>
<tr>
<td>lights</td>
<td>x:1A y:09</td>
<td>size: 00</td>
</tr>
<tr>
<td>lights</td>
<td>x:1A y:15</td>
<td>size: 00</td>
</tr>
<tr>
<td>lights</td>
<td>x:2F y:25</td>
<td>x:30 y:09</td>
</tr>
<tr>
<td>lights</td>
<td style="font-family:arial;">—</td>
<td>obj:80 x:3B y:11 <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td>x:2A y:14</td>
<td>x:27 y:14</td>
</tr>
<tr>
<td>wall</td>
<td>x:18 y:09</td>
<td>x:25 y:14 size:01</td>
</tr>
<tr>
<td>wall</td>
<td>x:2A y:18</td>
<td>x:27 y:18</td>
</tr>
<tr>
<td>cement</td>
<td>x:18 y:18</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>cement</td>
<td>x:28 y:18</td>
<td>x:26 y:18 <em>back</em></td>
</tr>
<tr>
<td>wall</td>
<td>x:2A y:1A</td>
<td>x:27 y:1A</td>
</tr>
<tr>
<td>wall</td>
<td>x:2D y:17</td>
<td>x:2A y:16 <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td>x:31 y:17</td>
<td>x:31 y:16 size:00</td>
</tr>
<tr>
<td>stairs</td>
<td style="font-family:arial;">—</td>
<td>obj:F9D x:2E y:16 <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:113 x:33 y:16 <em>back</em></td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:004 x:33 y:17 size:01 <em>back</em></td>
</tr>
<tr>
<td>water</td>
<td>x:30 y:0F</td>
<td>x:2E y:0F</td>
</tr>
<tr>
<td>water</td>
<td style="font-family:arial;">—</td>
<td>obj:0C8 x:36 y:0F size:01 <em>back</em></td>
</tr>
<tr>
<td>edge</td>
<td>x:30 y:0F</td>
<td>x:2D y:0F size:06 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td>x:30 y:0E</td>
<td>x:2D y:0E size:08 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td style="font-family:arial;">—</td>
<td>obj:044 x:2D y:16 size:06 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td>x:30 y:17</td>
<td>x:35 y:17 size:00</td>
</tr>
</tbody>
</table>
<p>Here&#8217;s what it looks like after you&#8217;re finished:</p>
<div id="attachment_39" class="wp-caption alignnone" style="width: 189px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_done_part1.png"><img class="size-medium wp-image-39" title="post4_done_part1" src="http://lthzelda.files.wordpress.com/2009/03/post4_done_part1.png?w=179&#038;h=127" alt="Our Entry Room to the Castle Basement is Complete" width="179" height="127" /></a><p class="wp-caption-text">Our Entry Room to the Castle Basement is Complete</p></div>
<p>You&#8217;ve learned a lot about from this, I hope. For example, you&#8217;ve learned that tiles can overlay like crazy, and the movement rules are determined in a very sensible, visible fashion. (This becomes less intuitive once you start using two layers). You may have also learned that if you left click on an object, then right-click and choose “Add Object”, the default object will be the type of the first object you clicked on. This makes it really easy to insert a new tile if you can see a similar one on-screen. It&#8217;s a real time-saver.</p>
<p><strong>Step 5: Doors and Staircases</strong></p>
<p>We now move on to one of the most difficult parts of dugeon editing: doors and staircases. Actually, that&#8217;s a lie: everything&#8217;s amazingly difficult. But doors (and staircases) require actual explaining, not just hex mangling, to really understand the concept. And then there&#8217;s that mind-numbing number pad “feature”, which I consider to be pure evil.</p>
<p>Backup your ROM and open the working copy in Hyrule Magic. (We can switch to Windows for a while, yes?) Now, click on layer 3 in “Edit”, and then right-click and choose “insert a door”. Scroll up to door 000, click on it, and click “Ok”.</p>
<div id="attachment_34" class="wp-caption alignnone" style="width: 214px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_add_new_door.png"><img class="size-medium wp-image-34" title="post4_add_new_door" src="http://lthzelda.files.wordpress.com/2009/03/post4_add_new_door.png?w=204&#038;h=165" alt="Add a New Door of Type 000" width="204" height="165" /></a><p class="wp-caption-text">Add a New Door of Type 000</p></div>
<p>Now, left-click on the door you just placed. This is where Hyrule Magic gets evil. You need to press the arrow keys <strong><em>on the number keypad</em></strong> in order to move the door around. The regular arrow keys won’t work. (On a laptop, you’ll have to use the function key, probably). In my opinion, this is a pure sin of interface design —why would you <em>ever </em>assign different functionality to these two sets of keys. Even Ctrl+Arrow is a better solution.</p>
<p>Press the right arrow until the “Pos” of your new door reads “8”. This may look a bit odd for now, but we’ll fix that later.</p>
<div id="attachment_45" class="wp-caption alignnone" style="width: 211px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_new_door_position.png"><img class="size-medium wp-image-45" title="post4_new_door_position" src="http://lthzelda.files.wordpress.com/2009/03/post4_new_door_position.png?w=201&#038;h=162" alt="Use the Number Pad's Arrow Keys to Move the Door" width="201" height="162" /></a><p class="wp-caption-text">Use the Number Pad&#39;s Arrow Keys to Move the Door</p></div>
<p>You can also add this door on layer 1. However, if you do that, the door on the left might disappear; you can manually add it back (it’s door type 001, but we’ll change that later.) A bigger problem is what happens if the entrance door disappears. If that is the case, you have to re-add it —and it can <em><strong>only be added to layer 3</strong></em>. Also, there are <strong><em>two </em></strong>doors which must be stacked to enforce the entrance. Do the following:</p>
<ul>
<li>First put down door type 02A and align it over where the exit was.</li>
<li>Then, put down door type 033 and move it directly <em><strong>over </strong></em>the door you just placed.</li>
<li>Now save. Your entrance functionality should have been restored. If not, make <em><strong>sure </strong></em>that you placed <em><strong>both </strong></em>doors on layer 3.</li>
</ul>
<p>Now that you’ve fixed the entrance (or maybe you were lucky and didn’t have to) you should add another door, of type 016, and move it to position 7. Finally, click on the left-most door (the one that was already there) and move it to position 6. Right-click on it, select “choose an object”, and change it to object 000.</p>
<p>I recommend keeping all doors in layer 3, but it’s up to you. Either way, save your game.</p>
<p>Our staircase, by the way, already works. If you look at the very southern part of the room, you can see that we have to climb a staircase before exiting the “Dungeon”. This implies that you enter the dungeon on the “ground level”. In reality, though, staircases usually work so long as you place the start and end bits on valid walkable ground. (In case you haven’t figured it out yet, the “depth” in Zelda3 is just an illusion.)  I don’t know enough about Zelda3 to know if you can just keep chaining staircases onto each other, but I’m going to try to stay consistent with the game until I feel adventurous. So, when I put that staircase in our small confined room, I knew that meant I was going to delete the other one.</p>
<p>Do that now: edit plane 1 and right-click on the staircase at 0E,34. Choose “Remove”. Save. We’ll fix the layout later.</p>
<p><strong>Step 6: An Arrow Puzzle</strong></p>
<p>We want to spice up our first Entrance with an arrow-only puzzle. My idea is to have a crystal switch the player sees as he falls in from the garden, and then have him walk around to the far door, then shoot an arrow over the gap at the crystal switch. The middle door is a red herring; there’s no way to get the big key yet. Maybe we can put a treasure chest there to reward the player later when he actually gets the big key.</p>
<p>Perform the following actions:</p>
<table style="font-family:courier;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td><strong><em>Comment</em></strong></td>
<td><strong><em>Before</em></strong></td>
<td><strong><em>After</em></strong></td>
</tr>
<tr>
<td>Comment:</td>
<td>Before:</td>
<td>After:</td>
</tr>
<tr>
<td>wall</td>
<td>x:14 y:14</td>
<td>x:22 y:14 <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td>x:14 y:18</td>
<td>x:22 y:18</td>
</tr>
<tr>
<td>wall</td>
<td>x:14 y:1A</td>
<td>x:22 y:1A</td>
</tr>
<tr>
<td>lights</td>
<td>x:11 y:1B</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>lights</td>
<td>x:0B y:1B</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:15 y:11</td>
<td>x:18 y:18 size:00</td>
</tr>
<tr>
<td>wall</td>
<td>x:11 y:17</td>
<td>x:19 y:18</td>
</tr>
<tr>
<td>wall</td>
<td>x:0B y:17</td>
<td>x:14 y:18</td>
</tr>
<tr>
<td>light</td>
<td>x:1A y:15</td>
<td>x:17 y:1B</td>
</tr>
<tr>
<td>wall</td>
<td>x:0F y:17</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:11 y:15</td>
<td>x:19 y:0E size:04</td>
</tr>
<tr>
<td>wall</td>
<td>x:0B y:0F</td>
<td>x:14 y:0E size:04</td>
</tr>
<tr>
<td>wall</td>
<td>x:0B y:0B</td>
<td>x:14 y:0B <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td>x:0F y:0B</td>
<td>x:18 y:0B size:00 <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td>x:2F y:0B</td>
<td>x:2D y:0B size:04</td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:10A x:19 y:0B <em>front</em></td>
</tr>
<tr>
<td>light</td>
<td>x:1A y:09</td>
<td>x:17 y:09</td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:069 x:13 y:0B size:0C</td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:069 x:1D y:0B size:0C</td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:069 x:29 y:0B size:00</td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:069 x:29 y:11 size:00</td>
</tr>
<tr>
<td>edge</td>
<td style="font-family:arial;">—</td>
<td>obj:79 x:17 y:0F size:08 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td style="font-family:arial;">—</td>
<td>obj:7A x:19 y:0F size:08 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td style="font-family:arial;">—</td>
<td>obj:3F x:17 y:0E size:00 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td style="font-family:arial;">—</td>
<td>obj:40 x:17 y:18 size:00 <em>front</em></td>
</tr>
<tr>
<td>water</td>
<td style="font-family:arial;">—</td>
<td>obj:0C8 x:17 y:0E size:02 <em>back</em></td>
</tr>
<tr>
<td>treasure</td>
<td>x:30 y:2C</td>
<td>obj:F99 x:22 y:0C Item: 73:sword 1 <em>front</em></td>
</tr>
</tbody>
</table>
<p>Switch to “Sprite” mode, right-click and choose “Insert an enemy”. Choose “PegSwitch” and click Ok. Put this one at x:24 y:0C. Repeat, and place the second one at x:20 y:0C. Then, right-click on each of the “Knight” sprites below and choose “Remove”. Now Save.</p>
<div id="attachment_49" class="wp-caption alignnone" style="width: 231px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_top_part_done.png"><img class="size-medium wp-image-49" title="post4_top_part_done" src="http://lthzelda.files.wordpress.com/2009/03/post4_top_part_done.png?w=221&#038;h=182" alt="The Top of Our Dungeon Room is Complete!" width="221" height="182" /></a><p class="wp-caption-text">The Top of Our Dungeon Room is Complete!</p></div>
<p>We’re beginning to get a feel for this dungeon: the player drops in, sees a switch, learns there’s no way he’s getting the big key, and then decides to hit the switch from the other side. Whew, what a lot of work! However, if you load the ROM in zsnes, you’ll notice a problem immediately:</p>
<div id="attachment_37" class="wp-caption alignnone" style="width: 200px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_crystal_switch_error.png"><img class="size-medium wp-image-37" title="post4_crystal_switch_error" src="http://lthzelda.files.wordpress.com/2009/03/post4_crystal_switch_error.png?w=190&#038;h=165" alt="Our Crystal Switches are All Shadowy" width="190" height="165" /></a><p class="wp-caption-text">Our Crystal Switches are All Shadowy</p></div>
<p>The problem is, all the enemies on one “level” use the same palette. The crystal switch is considered an enemy, so right now it is using a palette with nulled-out colors. Looking at the Perfect Guide, you can see that several palettes use PegSwitch: 15, 27, 26 and 10, to name a few. Open your ROM and change the “EnemyBlk” to “10”. Sometimes you’ll have to pair a palette up with a “blockset”. Eventually, you should be able to create custom groupings of blocks and colors for use in your dungeons.</p>
<p>By the way, change the “Blockset” from “16” to “1”. It’s not necessary, but it makes things look a lot more regal:</p>
<div id="attachment_38" class="wp-caption alignnone" style="width: 197px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_crystal_switch_fixed.png"><img class="size-medium wp-image-38" title="post4_crystal_switch_fixed" src="http://lthzelda.files.wordpress.com/2009/03/post4_crystal_switch_fixed.png?w=187&#038;h=163" alt="Proper Crystal Switches and a New Blockset" width="187" height="163" /></a><p class="wp-caption-text">Proper Crystal Switches and a New Blockset</p></div>
<p><strong>Step 7: Finishing Up the Arrow Puzzle</strong></p>
<p>We need to edit the lower half of Entrance 32. We could simply render it as a big square, with some blue crystal blocks impeding our exit. But that’s boring, and will make our audience groan for its lack of creativity. Let’s think: what kind of building did we fall into?</p>
<ul>
<li>The original garden entrance was… some weird, useless storage shed.</li>
<li>Now, we’ve got a locked door and a chest. (There’s a sword inside, but it could be changed to something more interesting… like flippers).</li>
<li>So we’re in a… control shack for Hyrule River?</li>
<li>Then the lower room should have lots of flowing water, and be a “public space” (no fancy jumping needed to get around).</li>
</ul>
<p>Hmm…. maybe we can also be more creative with the crystal blocks. Let’s use them as bridges. Perhaps the big key door is locked because it’s a control room for the “bridges”. We’ll have to think of a better explanation later (water purification? Ph testing?) but at least that’s more interesting than a big rectangle.</p>
<p>Ok, make the necessary changes.</p>
<ul>
<li>Switch to level 3, click on the door at position 6 (the exit) and press right (on the numpad) <strong><em>twice</em></strong>. Now, click on the <em>other </em>door at position 6 and press numpad-right twice. We’ve now moved the exit doors.</li>
<li>Switch to “Item” level, right-click on each “Magic” circle, and choose “Remove”.</li>
<li>Switch to “torch” level, right-click on our only torch, and choose “Remove”. Switch back to level 1.</li>
</ul>
<table style="font-family:courier;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td><strong><em>Comment</em></strong></td>
<td><strong><em>Before</em></strong></td>
<td><strong><em>After</em></strong></td>
</tr>
<tr>
<td>Comment:</td>
<td>Before:</td>
<td>After:</td>
</tr>
<tr>
<td>pedestal</td>
<td>x:2C y:2A</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:35 y:27</td>
<td>x:37 y:27</td>
</tr>
<tr>
<td>wall</td>
<td>x:38 y:28</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:28 y:24</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>cement</td>
<td>x:3C y:24</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:35 y:2B</td>
<td>x:37 y:29</td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:106 x:3A y:2C <em>back</em></td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:001 x:3E y:2C</td>
</tr>
<tr>
<td>wall</td>
<td>x:35 y:35</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:38 y:38</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:26 y:38</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>cement</td>
<td>x:22 y:3C</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:16 y:30</td>
<td>x:3A y:36</td>
</tr>
<tr>
<td>wall</td>
<td>x:1A y:30</td>
<td>x:3E y:36 size:01</td>
</tr>
<tr>
<td>wall</td>
<td>x:0D y:27</td>
<td>x:17 y:27 size:00</td>
</tr>
<tr>
<td>wall</td>
<td>x:2D y:27</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:09 y:27</td>
<td>x:13 y:27</td>
</tr>
<tr>
<td>wall</td>
<td>x:13 y:2D</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:13 y:31</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:13 y:34</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:09 y:2B</td>
<td>x:13 y:2B size:03</td>
</tr>
<tr>
<td>wall</td>
<td>x:0D y:34</td>
<td>x:15 y:33 size:04</td>
</tr>
<tr>
<td>wall</td>
<td>x:17 y:2D</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:25 y:2D</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:09 y:34</td>
<td>x:13 y:33 <em>front</em></td>
</tr>
<tr>
<td>cement</td>
<td>x:1A y:34</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:10A x:18 y:27 <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:10E x:18 y:2F</td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:003 x:1C y:2F</td>
</tr>
<tr>
<td>water</td>
<td style="font-family:arial;">—</td>
<td>obj:0C8 x:15 y:2D <em>front</em></td>
</tr>
<tr>
<td>water</td>
<td style="font-family:arial;">—</td>
<td>obj:0C8 x:15 y:31 size:04 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td style="font-family:arial;">—</td>
<td>obj:079 x:15 y:2B size:08 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td style="font-family:arial;">—</td>
<td>obj:07A x:19 y:2B size:05 <em>front</em></td>
</tr>
<tr>
<td>grate</td>
<td style="font-family:arial;">—</td>
<td>obj:FEF x:1B y:31 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td style="font-family:arial;">—</td>
<td>obj:045 x:19 y:31 <em>front</em></td>
</tr>
<tr>
<td>edge</td>
<td style="font-family:arial;">—</td>
<td>obj:040 x:15 y:34 size:04 <em>front</em></td>
</tr>
<tr>
<td>grate</td>
<td style="font-family:arial;">—</td>
<td>obj:FEC x:16 y:28</td>
</tr>
<tr>
<td>barrier</td>
<td>x:09 y:38</td>
<td>x:13 y:2A size:06 <em>front</em></td>
</tr>
<tr>
<td>barrier</td>
<td>x:12 y:38</td>
<td>x:13 y:2F size:08 <em>front</em></td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:022 x:13 y:36 size:08 <em>front</em></td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:069 x:13 y:27 size:00 <em>front</em></td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:069 x:1C y:27 size:00 <em>front</em></td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:069 x:13 y:2F size:04 <em>front</em></td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:069 x:1E y:2F size:04 <em>front</em></td>
</tr>
<tr>
<td>lights</td>
<td>x:11 y:25</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>lights</td>
<td>x:0B y:25</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:16 y:34</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:16 y:3A</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:22 y:38</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:22 y:30</td>
<td>x:20 y:3A</td>
</tr>
<tr>
<td>wall</td>
<td>x:22 y:34</td>
<td>x:20 y:3E size:01</td>
</tr>
<tr>
<td>wall</td>
<td>x:25 y:31</td>
<td>x:33 y:29 size:02</td>
</tr>
<tr>
<td>wall</td>
<td>x:25 y:35</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td>x:29 y:35</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>pot</td>
<td>x:33 y:31</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>pot</td>
<td>x:33 y:33</td>
<td style="font-family:arial;">—</td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:108 x:33 y:27 <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td>x:37 y:27</td>
<td><em>front</em></td>
</tr>
<tr>
<td>water</td>
<td style="font-family:arial;">—</td>
<td>obj:0C8 x:35 y:27 size:01 <em>front</em></td>
</tr>
<tr>
<td>grate</td>
<td style="font-family:arial;">—</td>
<td>obj:FEC x:35 y:27 <em>front</em></td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:022 x:32 y:2E size:0A <em>front</em></td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:022 x:32 y:37 size:0A <em>front</em></td>
</tr>
<tr>
<td>barrier</td>
<td style="font-family:arial;">—</td>
<td>obj:069 x:32 y:27 size:04 <em>front</em></td>
</tr>
</tbody>
</table>
<div id="attachment_46" class="wp-caption alignnone" style="width: 189px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_part2_reflection.png"><img class="size-medium wp-image-46" title="post4_part2_reflection" src="http://lthzelda.files.wordpress.com/2009/03/post4_part2_reflection.png?w=179&#038;h=140" alt="We're Nearly Done... Should We Add a Third Culvert?" width="179" height="140" /></a><p class="wp-caption-text">We&#39;re Nearly Done... Should We Add a Third Culvert?</p></div>
<p>Looks incomplete, no? At this point, I was going to add another minor waterway, but looking at the top screen, I noticed that it wouldn’t line up right. Originally, I was just going to say that some sewer line carried away the middle waterway –it looked pretty cool after all. But I think it’s actually better to leave this out.</p>
<p>Naturally, I create all of my tutorial ROMs twice: once to make sure the concept works and once to write out instructions for the blog post. But I want to stress the importance of reflecting on your design decisions: I had the third water-way in place on my first ROM, and decided not to add it on the second one.</p>
<p>Ok, let’s add the final pieces to our room:</p>
<table style="font-family:courier;" border="1" cellpadding="3" rules="all">
<tbody>
<tr>
<td><strong><em>Comment</em></strong></td>
<td><strong><em>Before</em></strong></td>
<td><strong><em>After</em></strong></td>
</tr>
<tr>
<td>Comment:</td>
<td>Before:</td>
<td>After:</td>
</tr>
<tr>
<td>bridge</td>
<td style="font-family:arial;">—</td>
<td>obj:0B9 x:13 y:2B size:05 <em>front</em></td>
</tr>
<tr>
<td>bridge</td>
<td style="font-family:arial;">—</td>
<td>obj:0B9 x:13 y:2D size:05 <em>front</em></td>
</tr>
<tr>
<td>water</td>
<td style="font-family:arial;">—</td>
<td>obj:0C9 x:30 y:2F size:0D <em>front</em></td>
</tr>
<tr>
<td>water</td>
<td style="font-family:arial;">—</td>
<td>obj:0C9 x:1F y:2F size:0D <em>front</em></td>
</tr>
<tr>
<td>water</td>
<td style="font-family:arial;">—</td>
<td>obj:0C9 x:23 y:34 size:06 <em>front</em></td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:107 x:2A y:3A <em>back</em></td>
</tr>
<tr>
<td>wall</td>
<td style="font-family:arial;">—</td>
<td>obj:062 x:2A y:3E size:01 <em>back</em></td>
</tr>
<tr>
<td>bridge</td>
<td style="font-family:arial;">—</td>
<td>obj:092 x:1F y:2F size:04 <em>front</em></td>
</tr>
<tr>
<td>bridge</td>
<td style="font-family:arial;">—</td>
<td>obj:092 x:21 y:2F size:04 <em>front</em></td>
</tr>
<tr>
<td>bridge</td>
<td style="font-family:arial;">—</td>
<td>obj:092 x:2D y:2F size:04 <em>front</em></td>
</tr>
<tr>
<td>bridge</td>
<td style="font-family:arial;">—</td>
<td>obj:092 x:2F y:2F size:04 <em>front</em></td>
</tr>
</tbody>
</table>
<p>And we’re done! (You guys didn’t notice that I forgot that corner, did you?)</p>
<div id="attachment_40" class="wp-caption alignnone" style="width: 175px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_final_shot.png"><img class="size-medium wp-image-40" title="post4_final_shot" src="http://lthzelda.files.wordpress.com/2009/03/post4_final_shot.png?w=165&#038;h=125" alt="Our Completed Room" width="165" height="125" /></a><p class="wp-caption-text">Our Completed Room</p></div>
<p>Our puzzle is complete. Back up your ROM, please, since we’re going to be hacking the header next. When you run your ROM, you can solve the puzzle easily and exit the room. (There is a weird glitch where sometimes the screen won’t scroll properly after walking up the stairs for the first time. I’ve designed this room so that it won’t hinder your progress, but I’m not sure exactly how to fix that bug if it occurs again.) However, something’s amiss if you then re-enter the room. You’re in the wrong starting location!</p>
<div id="attachment_50" class="wp-caption alignnone" style="width: 220px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_wrong_entrance.png"><img class="size-medium wp-image-50" title="post4_wrong_entrance" src="http://lthzelda.files.wordpress.com/2009/03/post4_wrong_entrance.png?w=210&#038;h=183" alt="Entering From the Original Location, Only Now the Door's Gone" width="210" height="183" /></a><p class="wp-caption-text">Entering From the Original Location, Only Now the Door&#39;s Gone</p></div>
<p>Open Hyrule Magic (make <em>sure </em>you’ve backed up your ROM) and look in the “Starting Location” tab. You’ll see “Room”, which we won’t change, and then “X” and “Y” which we will. You can do the math to set these properly (each tile is 16 pixels wide and high) but I prefer to just switch to a room with a similar entrance and copy the values from there. We’ll also need to adjust the x-scroll value to start our camera further over to the right. And, we should fix the CX and CY values as described in the <em>Perfect Guide</em>. Change the following:</p>
<p><code style="color:black;font-weight:bold;">X = 376<br />
xScroll = 256<br />
CX = xScroll + 128 = 256+128 = 384<br />
CY = yScroll + 112 = 272 + 112 = 384<br />
</code></p>
<p>Please click on the “More” button in the <strong>top </strong>part of the Dungeon editor, then click “Ok”. Then Save. Sometimes Hyrule Magic won’t persist room values if you don’t click the “more” button; I have no idea why.</p>
<p>Open your ROM, and re-test… whoah! You’re colliding with obstacles that aren’t there, and you’re jumping into ground that’s really water:</p>
<div id="attachment_41" class="wp-caption alignnone" style="width: 190px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_glitched_startx.png"><img class="size-medium wp-image-41" title="post4_glitched_startx" src="http://lthzelda.files.wordpress.com/2009/03/post4_glitched_startx.png?w=180&#038;h=156" alt="Jumping Into the Wall? Must Have Mis-Aligned the Camera" width="180" height="156" /></a><p class="wp-caption-text">Jumping Into the Wall? Must Have Mis-Aligned the Camera</p></div>
<p>It’s almost like Hyrule Magic is ignoring the value we entered for xScroll. And… if you open your ROM and double-check, <strong><em>it is ignoring it</em></strong>! This is another frustrating feature of Hyrule Magic; sometimes it doesn’t really save your data. You’ll understand why after we cover the ridiculously complex way that Zelda3 saves the xScroll parameter. For now, it’s sandwich time. I recommend a BLT.</p>
<p><strong>Step 8: Fixing the xScroll Wonkiness</strong></p>
<p>You’ll need a hex editor. We’ll cover Windows first. I recommend using <a href="http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm">XVI32</a>.  Open the program, then open your Zelda3.smc ROM. We are now presented with the first few bytes of the file. They’re all header space, so they’re not too interesting. On the left is the hexadecimal view, and on the right is the ASCII view. Scroll down a bit and you’ll see what I mean:</p>
<div id="attachment_51" class="wp-caption alignnone" style="width: 200px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_xvi32.png"><img class="size-medium wp-image-51" title="post4_xvi32" src="http://lthzelda.files.wordpress.com/2009/03/post4_xvi32.png?w=190&#038;h=162" alt="A Typical Day With Your Hex Editor of Choice" width="190" height="162" /></a><p class="wp-caption-text">A Typical Day With Your Hex Editor of Choice</p></div>
<p>In this example, we are in position 0xEB589, which has the value 4B. In ASCII, that would be the letter “K”, but probably this is actually just used as a number for something, not as a letter. A lot of the data in Zelda3 is compressed, so you won’t be able to find it even if you know what you’re looking for.</p>
<p>At the bottom of the screen, you can see that 0x4B is actually the number 75. Also, you can see that “Overwrite” is on. As you may recall from the early days of Microsoft Word, this means that typing a letter will erase the next letter, so that you never expand the length of the document. Unlike Word, you <strong><em>almost always</em></strong> want this on when hex editing. Otherwise, you’ll offset the entire ROM, and data won’t load where it’s supposed to. Don’t worry, you’ll notice if you do this when you open the ROM; it’s almost guaranteed not to load at all.</p>
<p>From the <em>Perfect Guide</em>, we know that <strong>xScroll </strong>for the dungeons starts at 0x14F45 and each value is 2 bytes in length. Since we want the data for Entrance 0&#215;32, we do some simple math in Windows Calculator (hex mode) and get:</p>
<p><code style="color:black;">14F45 + 32*2 = 14FA9</code></p>
<p>Hitting “Ctrl+G” in XVI32, we click “hexadecimal” under “Go to”, ensure that our “Go mode” is “absolute”, and type in 14FA9. Click “Ok”, and our cursor jumps to address 0x14FA9.</p>
<p>The highlighted box reads 00, and the next box to the right reads 0A. Since Zelda3 stores bytes backwards, we read this as 0x0A00, or 2560 …which is <strong><em>not </em></strong>zero, as we might expect. Enter 2560 in Windows Calculator and click “Bin” to convert this to binary. Now, we have:</p>
<p><code style="color:red;font-weight:bold;">101</code><code style="color:green;font-weight:bold;">000000000</code></p>
<p>Note the green bits. Zelda3 uses these for… something, and it prevents Hyrule Magic from saving the xscroll value properly. The red bits are the actual bits used for saving xscroll. So, if we want an x-scroll of 256, then we need:</p>
<p><code style="color:red;font-weight:bold;">101</code><code style="color:green;font-weight:bold;">100000000</code></p>
<p>…since 100000000 in binary is 256 in decimal notation. (Generally, you won’t want to mess with the green bits).</p>
<p>If you enter 101100000000 into your calculator and then switch to hexadecimal, you get 0x0B00. Breaking apart and flipping the bytes, we get:</p>
<p><code style="color:black;font-weight:bold;">00 0B</code></p>
<p>So, in XVI 32, click once on the 0A next to the cursor to move it there, type <strong>0B </strong>and then Save. Load the ROM in Hyrule Magic and you’ll see that our <strong>xScroll </strong>has, in fact, been updated. Load it in zsnes and you’ll notice that our scrolling problem is gone.</p>
<div id="attachment_48" class="wp-caption alignnone" style="width: 183px"><a href="http://lthzelda.files.wordpress.com/2009/03/post4_scrolling_works.png"><img class="size-medium wp-image-48" title="post4_scrolling_works" src="http://lthzelda.files.wordpress.com/2009/03/post4_scrolling_works.png?w=173&#038;h=150" alt="Hooray! Let's Go for a Swim!" width="173" height="150" /></a><p class="wp-caption-text">Hooray! Let&#39;s Go for a Swim!</p></div>
<p><strong>Step 8.2: Fixing the Wonkiness on Linux</strong></p>
<p>I’m still looking for a good hex editor on Ubuntu, so if you have any suggestions, please let me know. For now, you should use tweak, a console editor with a slight Emacs inclination.</p>
<p><code style="color:black;">sudo apt-get install tweak</code></p>
<p>Please read the previous section on Windows to understand how we do the math. Basically, we just want to replace the <strong>0A </strong>at offset <strong>14FAA </strong>with an <strong>0B</strong>. To do this:</p>
<p><code style="color:black;">tweak Zelda3.smc<br />
Then, press Ctrl+X then g<br />
Then type <strong>0x14FAA</strong> and hit <strong>Enter</strong>.<br />
Then type <strong>0B </strong>and press Ctrl+X then Ctrl+S<br />
Then press Ctrl+X then Ctrl+C</code></p>
<p>Okay, we’ve edited our file, saved it, and exited. Re-run our game, and you’ll see that Link is back where he should be when entering the room.</p>
<p><em><strong>Possible Improvement</strong></em></p>
<p>Here’s a summary of some things I’d like to modify, but had no time to. You can play around with them, if you’d like:</p>
<ul>
<li>Change the opening message from Link’s uncle to make more sense.</li>
<li>Re-arrange Entrance 00 (Link’s house, pre-Intro) to  have a more intelligent layout. The chest should go in front of his bed, for example, or maybe he should have two chests; one with the bow and one with arrows.</li>
<li>Change the messages from Zelda, and the message when you pick up your bow so that they make more sense.</li>
<li>Advanced. You actually can’t save; it will drop you back off at the introduction. This is (I think) because the “Castle” save flag is set when your Uncle gives you your sword. Read through the <em>Perfect Guide</em> and <em>MON’s Pinups</em> until you know what has to be changed, and write a small hack which fixes this. (Maybe you can set the “Castle” save flag when Link falls into the hole?)</li>
<li>If you play through the intro a bit, you’ll notice that arrows are in short supply, and that the ball-and-chain trooper goes down with a mere four arrows. Also, the lamp should be harder to get (maybe in that chest we put between the crystal switches?) and the boomerang should be acquired later. Fiddle around and fix these. Also, consider making more arrow-related puzzles in Hyrule Castle. Just remember that it is a castle, after all, so maintain a believable architecture.</li>
<li>For the hardcore players, devise a way for them to get into the basement without even the bow. (Make it very tricky to figure out.) This means they have to beat the entire castle by throwing pots. Trust me, hardcore players will love you for this.</li>
<li>Add a telepathic tile to the water control room which helps to clarify its purpose. (Hint: click on the “more” button on the top of the dungeon window).</li>
</ul>
<p><strong>Credits</strong></p>
<p>In addition to the <em>Perfect Guide</em>, I relied heavily on MathOnNapkins’s “<a href="http://www.romhacking.net/docs/365/">Zelda 3 ROM Map</a>”, adding 0&#215;200 to the offsets since I’m using a headered ROM. I generally refer to these as <em>MON’s Pinups</em> in this guide.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/33/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=33&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2009/03/19/lz-2-bow-arrow-quest/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_mess_up.png?w=300" medium="image">
			<media:title type="html">post4_mess_up</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_jump_to_room.png?w=300" medium="image">
			<media:title type="html">post4_jump_to_room</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_remove_obj.png?w=300" medium="image">
			<media:title type="html">post4_remove_obj</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_add_new_object.png?w=300" medium="image">
			<media:title type="html">post4_add_new_object</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_move_to_front.png?w=300" medium="image">
			<media:title type="html">post4_move_to_front</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_change_item_to_bow.png?w=300" medium="image">
			<media:title type="html">post4_change_item_to_bow</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_done_part1.png?w=300" medium="image">
			<media:title type="html">post4_done_part1</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_add_new_door.png?w=300" medium="image">
			<media:title type="html">post4_add_new_door</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_new_door_position.png?w=300" medium="image">
			<media:title type="html">post4_new_door_position</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_top_part_done.png?w=300" medium="image">
			<media:title type="html">post4_top_part_done</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_crystal_switch_error.png?w=300" medium="image">
			<media:title type="html">post4_crystal_switch_error</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_crystal_switch_fixed.png?w=300" medium="image">
			<media:title type="html">post4_crystal_switch_fixed</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_part2_reflection.png?w=300" medium="image">
			<media:title type="html">post4_part2_reflection</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_final_shot.png?w=300" medium="image">
			<media:title type="html">post4_final_shot</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_wrong_entrance.png?w=300" medium="image">
			<media:title type="html">post4_wrong_entrance</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_glitched_startx.png?w=300" medium="image">
			<media:title type="html">post4_glitched_startx</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_xvi32.png?w=300" medium="image">
			<media:title type="html">post4_xvi32</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post4_scrolling_works.png?w=300" medium="image">
			<media:title type="html">post4_scrolling_works</media:title>
		</media:content>
	</item>
		<item>
		<title>[LZ-1] Very Simple Introduction to Hyrule Magic</title>
		<link>http://lthzelda.wordpress.com/2009/03/15/lz-1-very-simple-introduction-to-hyrule-magic/</link>
		<comments>http://lthzelda.wordpress.com/2009/03/15/lz-1-very-simple-introduction-to-hyrule-magic/#comments</comments>
		<pubDate>Sun, 15 Mar 2009 05:39:08 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=23</guid>
		<description><![CDATA[In which we fiddle around with Hyrule Magic and change various miniscule things. <a href="http://lthzelda.wordpress.com/2009/03/15/lz-1-very-simple-introduction-to-hyrule-magic/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=23&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em><strong>Blog Info</strong></em>: <em>I wrote a short hack for <a href="http://datacrystal.org/wiki/List_of_Super_Mario_World_hacks"><strong><span style="color:#0000ff;">Super Mario World</span></strong></a> a while ago using Lunar Magic. Like most hacks, it was unfairly difficult, gimmicky, and had rather long levels. That’s when I really appreciated the challenge of game design. Years, later, playing <a href="http://developer.valvesoftware.com/wiki/Creating_a_rotating_portalgun"><strong><span style="color:#0000ff;">Portal</span></strong></a>, I was impressed by the impact of small, well-designed levels. And unlike my hack, the small levels had multiple solutions, so that lazy skilled players could innovate with some complex procedure while newbies had fun just figuring out the basic puzzle. And that’s when I turned my attention back to ROM hacking. </em></p>
<p><em><strong>Back-story</strong></em>:  ROM hacking really constrains your options. Zelda 3 has a fully-featured map editor, so you’d think that you have the power to re-arrange and re-create rooms like a giant jigsaw puzzle… except that some of the pieces must be in one place, and some of them will automatically re-write themselves with something else. So today, we’ll just take a very shallow dip into the waters of <a href="http://www.zophar.net/utilities/sneslevel/hyrule-magic.html"><strong><span style="color:#0000ff;">Hyrule Magic</span></strong></a>, and end with an extra-long discussion section in preparation for next week.</p>
<p><em><strong>Goal</strong></em>: Fiddle with the opening scene of LttP, changing graphics, text, and object placement.</p>
<p>Now, before we get started, let&#8217;s verify that we have the same file.</p>
<p><em>On Windows:</em></p>
<ul>
<li>Make a file named “Zelda3.hash” in the same directory as your ROM, with the contents:</li>
<pre style="color:black;">       1a74468291b02729329dd1357afb45af *<strong><span style="color:#ff0000;">Zelda3.smc</span></strong></pre>
<li> Make sure you switch <span style="color:#ff0000;"><strong>Zelda3.smc</strong></span> with your ROM’s name. You can download “Checksum” from <a href="http://corz.org/windows/software/checksum/"><strong><span style="color:#0000ff;">this link</span></strong></a>. Install it and double-click on your .hash file. You should get a message that the checksum is valid.</li>
</ul>
<p><em>On Linux:</em></p>
<ul>
<li> Make a file named “Zelda3.hash” in the same directory as your ROM, with the contents:</li>
<pre style="color:black;">       Jacksum: Meta-Info: version=1.7.0;algorithm=md5;filesep=/;encoding=hex;</pre>
<pre style="color:black;">       1a74468291b02729329dd1357afb45af <span style="color:#ff0000;"><strong>Zelda3.smc</strong></span></pre>
<li> (Make sure to replace <span style="color:#ff0000;"><strong>Zelda3.smc</strong></span> with your ROM&#8217;s name).</li>
<li>Install the “Jacksum” package:</li>
<pre style="color:black;">       sudo apt-get install jacksum</pre>
<li> &#8230;and run this simple check from the command line:</li>
<li>
<pre style="color:black;">       jacksum -c Zelda3.hash</pre>
</li>
<li> You should get an “Ok” message.</li>
</ul>
<p>Normally I&#8217;d just post the valid file, but I&#8217;m not allowed to distribute it unless you also own Zelda3. Sorry for the inconvenience. By the way, if your checksum fails, you can still try editing the ROM in Hyrule Magic, with some chance of success. (For example, your ROM may be headerless).</p>
<p>Please note that Hyrule Magic can royally screw up your ROM. Sometimes this is your fault (i.e., loading an expanded ROM), sometimes it is a bug in the editor, and sometimes it’s a feature of the Zelda3 ROM (e.g., “whoops, that tile can only be used for doors”) and you have no idea how to undo such changes. For this reason, it is <span style="color:#ff0000;"><em><strong>highly </strong></em></span>recommended that you keep rolling backups of your project files, even moreso than you would normally. I’m still looking for a VCS that handles binary files well, so for now I’d just recommend daily backups to USB and server-side backups every time you accomplish anything time-consuming.</p>
<p><strong> A Note About Linux</strong></p>
<p>As you might have guessed, we&#8217;ll be using Linux for this tutorial. Why, you ask? Well, first of all, <a href="http://appdb.winehq.org/objectManager.php?sClass=application&amp;iId=9387"><strong><span style="color:#0000ff;">because we can</span></strong></a>, and I want to be fair to all homebrew developers. Secondly, I&#8217;ve got a grand goal of making a <a href="http://rudd-o.com/new-projects/portablelinux"><strong><span style="color:#0000ff;">totally portable, OS-included thumb drive</span></strong></a>, and that requires me to learn Linux. Don&#8217;t worry, you can follow this tutorial on Windows (I&#8217;ve tested it on both). Here we go!<br />
<strong> Moving Objects, Changing Message Text</strong></p>
<p>Our goal today is a simple, shallow proof-of-concept hack. Copy the Zelda3 ROM to a new directory, then open Hyrule Magic, click “File -&gt; Open”, and browse to the new copy. Once you open the ROM, a whole list of menu items will appear.</p>
<div id="attachment_25" class="wp-caption alignnone" style="width: 179px"><a href="http://lthzelda.files.wordpress.com/2009/03/post3_hyrule_magic_options.png"><img class="size-medium wp-image-25" title="post3_hyrule_magic_options" src="http://lthzelda.files.wordpress.com/2009/03/post3_hyrule_magic_options.png?w=169&#038;h=168" alt="Tree-List of Options Available to You in Hyrule Magic" width="169" height="168" /></a><p class="wp-caption-text">Tree-List of Options Available to You in Hyrule Magic</p></div>
<p>This list is a categorical view of all the data from the Zelda3 ROM that Hyrule Magic understands. Click on “Dungeons” and then double click on “Entrance 00”. Zelda3&#8242;s dungeons are set up in a grid-like fashion, and the first one just happens to be your Uncle&#8217;s house. You can click and drag various objects –try dragging the table in front of the door:</p>
<div id="attachment_27" class="wp-caption alignnone" style="width: 170px"><a href="http://lthzelda.files.wordpress.com/2009/03/post3_move_the_table.png"><img class="size-medium wp-image-27" title="post3_move_the_table" src="http://lthzelda.files.wordpress.com/2009/03/post3_move_the_table.png?w=160&#038;h=105" alt="Dragging the Table in Front of the Door" width="160" height="105" /></a><p class="wp-caption-text">Dragging the Table in Front of the Door</p></div>
<p>Hit “Ctrl+S” to save your ROM and “Ctrl+F4” to close the dungeon editor window. Double-click on “Dungeons” to compress the list, then double-click on “Monologue” to edit the game&#8217;s text. Double-click on the line which reads:</p>
<pre style="color:black;">[Name], I'm going out for a[2]while.  I'll be back by morning.[3]Don't leave the house.</pre>
<p>This is the first thing your Uncle says to you after Zelda&#8217;s message arrives in your head. The <strong>[Name]</strong> will be replaced by your character&#8217;s name. The <strong>[2]</strong> and <strong>[3]</strong> indicate where the second and third lines begin. Change the text to read:</p>
<pre style="color:black;">[Name], you sneak out too much.[2]I've blocked the exit.[3]You can't leave now!</pre>
<p>Then click the “Set” button. In the same way, change message 32:</p>
<p><tt>[Window 02][Speed 03]Help me...[2]I am in the dungeon of the[3]castle.[Waitkey][Scroll]I know there is a hidden path[Scroll]from outside of  the castle to [Scroll]the garden inside.</tt></p>
<p>&#8230;to:</p>
<pre style="color:black;">[Window 02][Speed 03][2]Zelda here... [3]didn't you learn how to jump?</pre>
<p>Save your ROM (Ctrl+S) and close Hyrule Magic. You can now test the Zelda3 ROM you just hacked. <a href="http://www.zsnes.com/"><span style="color:#0000ff;"><strong>Zsnes</strong></span></a> works on most Linux boxes:</p>
<pre style="color:black;">zsnes /media/Windows/myProject/Zelda3.smc</pre>
<p>&#8230;or just open Zsnes and browse to the ROM. Go through the opening sequence; boy you&#8217;re stuck now!</p>
<div id="attachment_28" class="wp-caption alignnone" style="width: 152px"><a href="http://lthzelda.files.wordpress.com/2009/03/post3_zelda_mocks_you.png"><img class="size-medium wp-image-28" title="post3_zelda_mocks_you" src="http://lthzelda.files.wordpress.com/2009/03/post3_zelda_mocks_you.png?w=142&#038;h=129" alt="Link's Uncle Can Walk Over the Table, But Link Cannot" width="142" height="129" /></a><p class="wp-caption-text">Link&#39;s Uncle Can Walk Over the Table, But Link Cannot</p></div>
<p><strong>Palette Hacking</strong></p>
<p>Well, that was fun; let&#8217;s do one more quick hack and call it a day. Open your ROM in Hyrule Magic, and expand “Palettes”, then “Clothes”, then double-click “Clothes pal 0”. Like most SNES games, Zelda3 stores each pixel it draws by reference to a “palette”. If you were to change, say, the “white” color referenced in the “sword” palette, that would affect every white pixel in Link&#8217;s sword. Right now, we&#8217;re going to change the color of Link&#8217;s clothes. You should see:</p>
<div id="attachment_24" class="wp-caption alignnone" style="width: 137px"><a href="http://lthzelda.files.wordpress.com/2009/03/post3_clothes_palette.png"><img class="size-medium wp-image-24" title="post3_clothes_palette" src="http://lthzelda.files.wordpress.com/2009/03/post3_clothes_palette.png?w=127&#038;h=213" alt="A Swath of Colors Used to Paint Link's Character" width="127" height="213" /></a><p class="wp-caption-text">A Swath of Colors Used to Paint Link&#39;s Character</p></div>
<p>Count the colors from the left: “1, 2, 3&#8230;”. So color “5” is black. You can change a color by single-clicking on it and choosing a new one. Change the following:</p>
<pre style="color:black;">       Color 8 from pink to yellow. <span style="color:#009900;"><strong>(Did anyone else notice Link had pink hair?)</strong></span>
       Color 6 from orange to dark blue.
       Color 11 from green to matte blue.
       Color 12 from lime green to matte yellow.
       Color 2 from yellow to very dark red.
       Color 9 from green to a brighter green.
       Color 10 from green to a slightly lighter green than color 9.</pre>
<p>This isn&#8217;t scientific; just pick colors you like, really. Now, save and load your ROM. Link&#8217;s makeover is complete:</p>
<div id="attachment_26" class="wp-caption alignnone" style="width: 159px"><a href="http://lthzelda.files.wordpress.com/2009/03/post3_links_nightcap.png"><img class="size-medium wp-image-26" title="post3_links_nightcap" src="http://lthzelda.files.wordpress.com/2009/03/post3_links_nightcap.png?w=149&#038;h=137" alt="Looks a Bit Like a Nightie..." width="149" height="137" /></a><p class="wp-caption-text">Looks a Bit Like a Nightie...</p></div>
<p>You may have noticed that Link&#8217;s face gets all messed up if you pull something. This is not a bug; when we changed orange to dark blue, we affected more than just the trim on Link&#8217;s hat. If you were serious about changing Link&#8217;s color scheme, you&#8217;d probably have to edit the pixels which make up Link&#8217;s graphics in addition to the palettes.</p>
<p>Go make yourself a sandwich –or a coffee– we&#8217;ll be back after a short break.</p>
<p><em><strong>Required Reading</strong></em></p>
<p>You can skip this section if you like; it’s about game design, not hacking. But I think you should read it. Yes, you <em>have </em>to. That’s right.</p>
<p>While you eat your sandwich and drink your coffee, think about your target audience. Realistically, the only people who’d want to play your hack are ones who’ve already beaten Zelda3 multiple times. Probably, you’re one of these people too. So how can you cater to their particular needs?</p>
<p>Well, for one thing, the castle gets pretty boring after you’ve played the later dungeons.</p>
<p>We’re going to use a tried-and-true method of Zelda <a href="http://www.gamefaqs.com/console/nes/file/563433/49023"><span style="color:#0000ff;"><strong>power-questers</strong></span></a> today: we’ll deny the players use of the sword for the first bit of the game. The lantern, unfortunately, is a pretty lousy weapon, so let’s give the player some arrows; that should allow for some interesting puzzle construction. But what should we do about Link’s uncle? I see two possible solutions:</p>
<p><strong>The Hacker’s Solution</strong>: Scan the ROM and determine the code which gives Link the sword. Switch it so that Link’s uncle gives him the bow. Perhaps alter his sprite to be holding the bow, too.</p>
<p><strong>The Storyteller’s Solution</strong>: Just give the bow to Link at his house and delete his uncle in the palace basement; the story can be molded to fit around this.</p>
<p>I’m inclined to go with solution number two —it opens up a lot of creative possibilities. Solution 1 is a bit show-offy, and it doesn’t really fit so well into the story for Link’s uncle to give him anything except a sword. At this point, it’s good to brainstorm and consider a few potential trip-ups, and some tentative solutions (lest we back ourselves into a corner).</p>
<p><strong>Will Link Meet His Uncle Later?</strong> Maybe, but we won’t be able to have him in his “wounded” state giving Link anything, since this glitches the game after Zelda is rescued. We have his walkabout graphic; maybe we can replace one of the villagers with him. Or, we can have a mutant in the Dark World say he’s him. Or, we can change the ending credits from “Your Uncle Recovers” to “Your Uncle is Found”.</p>
<p><strong>Why Does Link Have a Bow in His House?</strong> Maybe he’s a hunter? Actually, it makes a lot more sense for him to have a bow than a sword. Maybe we can change the general feel of Zelda3 to be more “woodsy” and less “running from the law”.</p>
<p><strong>What About the Game Text?</strong> Link’s uncle can say anything; even the same message he says now. Zelda’s second message is easy to replace; something like “Half past the hour; all citizens to bed!”. The first message is tricky. We can have Sora Link monologue (“I’ve been having these… weird thoughts lately.”). Or, we can have him dreaming of his Uncle scolding him for playing around with his bow. Be creative.</p>
<p><strong>Will Link Be Able to Get the Sword Later?</strong> This is a very good question, especially if your Uncle can never give you the sword. Can you put it in a chest? At the very least, you can get the Master Sword, so that’ll be our backup.</p>
<p>This was a bit of a digression, but I wanted to impress the importance of thinking creatively and creating a world of your own. The hacker’s solution is elegant, but it actually creates a game that “feels” wrong. The lantern was added to your house to make it feel like you were heading out into the rain, to rescue a princess from some unspecific evil. I’ve always felt this was poorly done in the original game. Grabbing your bow and rushing out into the rain is a lot more romantic. (Stumbling upon your uncle and nabbing his bow is… a non sequitor.)</p>
<p>Even if you were the best ASM hacker in the world, you still shouldn’t desire to change everything. At that point, you might as well just develop an entirely new game. Rather, you want to make a game that plays like Zelda3, but feels totally different. I always take the Quest for Calatia as my inspiration. Here are two innovations this developer makes:</p>
<ul>
<li>He uses different trees and houses to imply that Calatia is a colder country.</li>
<li>He allows you to climb onto house rooftops and <a href="http://www.questforcalatia.net/Zelda3C/arch2006-1.html"><strong><span style="color:#0000ff;">hookshot between chimneys</span></strong></a>.</li>
</ul>
<p>Those two simple changes really expand the player’s mind as he is exploring. He feels like the fully-equipped link from Hyrule exploring a place which forces him to adapt his strategy.</p>
<p>Another example of great innovation uses ASM:</p>
<ul>
<li>Someone modified the game so that you can throw bombs in eight directions, and can throw them either a long distance or a short one.</li>
</ul>
<p>This mod subtly changes the nature of bombs into something much more utilitarian. I’m sure you could come up with all sorts of puzzles involving bombs and moving platforms, or switches that must be bombed simultaneously.</p>
<p><strong> Credits</strong><br />
My early blog entries on Hyrule Magic owe a lot to <a href="http://www.romhacking.net/docs/314/"><span style="color:#0000ff;">O<strong>rochimaru&#8217;s Perfect Guide to Zelda 3 Editing</strong></span></a>, an in-depth handbook to using this complex and sometimes non-intuitive editor. Feel free to refer to the Perfect Guide on your own time –it&#8217;s got lots of great info.</p>
<p><em><strong>Post Posting Post: </strong></em>Looking at my dashboard, it seems that a lot of people are finding this post after searching for <em><strong>sprite </strong></em>editing. Like &#8220;how do I edit Link&#8217;s graphics&#8221;? instead of just his palette. Believe me, I understand the frustration of getting no good hits on Google. So, I promise to add some sprite hacking to my next tutorial. I can&#8217;t just tell you now, since a lot of the graphics in Zelda are compressed, so it&#8217;s more complex than that, and I&#8217;m in the middle of another RPG Maker article at the moment.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/23/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=23&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2009/03/15/lz-1-very-simple-introduction-to-hyrule-magic/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post3_hyrule_magic_options.png?w=300" medium="image">
			<media:title type="html">post3_hyrule_magic_options</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post3_move_the_table.png?w=300" medium="image">
			<media:title type="html">post3_move_the_table</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post3_zelda_mocks_you.png?w=300" medium="image">
			<media:title type="html">post3_zelda_mocks_you</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post3_clothes_palette.png?w=178" medium="image">
			<media:title type="html">post3_clothes_palette</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/03/post3_links_nightcap.png?w=300" medium="image">
			<media:title type="html">post3_links_nightcap</media:title>
		</media:content>
	</item>
		<item>
		<title>[RM-2] Speech Balloons for NPCs</title>
		<link>http://lthzelda.wordpress.com/2009/02/24/rm-2-speech-balloons-for-npcs/</link>
		<comments>http://lthzelda.wordpress.com/2009/02/24/rm-2-speech-balloons-for-npcs/#comments</comments>
		<pubDate>Tue, 24 Feb 2009 05:02:46 +0000</pubDate>
		<dc:creator>sorlokreaves</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lthzelda.wordpress.com/?p=17</guid>
		<description><![CDATA[Blog Info: I originally started this blog with The Legend of Zelda: A Link to the Past in mind. I got hooked after reading this hacker’s blog. Sometimes teaching is the best way to learn, so I decided to do &#8230; <a href="http://lthzelda.wordpress.com/2009/02/24/rm-2-speech-balloons-for-npcs/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=17&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><strong><em>Blog Info</em></strong>: <em>I originally started this blog with <a href="http://www.lttp.net/arsenal.php"><span style="color:#0000ff;"><strong>The Legend of Zelda: A Link to the Past</strong></span></a> in mind. I got hooked after reading <strong><a href="http://www.questforcalatia.net/Zelda3C/diary.html"><span style="color:#0000ff;">this hacker’s blog</span></a></strong>. Sometimes teaching is the best way to learn, so I decided to do a series of “mini-tutorials”, each building on the previous one. I later decided to post <strong>any </strong>tutorial fitting this rubric, since the number of Zelda3 hackers is so small (and since my expertise lies far outside of ROM hacking). I hope to eventually post tutorials on <a href="http://www.romhacking.net/docs/314/"><strong><span style="color:#0000ff;">Hyrule Magic</span></strong></a>, <a href="http://www.angelfire.com/sk2/snesres/smw/lunar.shtml"><strong><span style="color:#0000ff;">Lunar Magic</span></strong></a>, and maybe even the <a href="http://exult.sourceforge.net/studio.php"><strong><span style="color:#0000ff;">Exult</span></strong></a> engine.</em></p>
<p><strong><em>Back-story</em></strong>:  Forcing the player to press “Enter” simply to hear what an NPC has to say is rather obnoxious. Wouldn’t it be better if NPCs simply “shouted” their messages out loud? Xenosaga Episode 3 did something similar; how hard can it be in RPG Maker VX?</p>
<p><strong><em>Goal</em></strong>: Make a light-weight Window that appears over an NPC’s head and shows what he’d normally say using the “Show Text” command.</p>
<p>Let’s start with a basic Window subclass, and an NPC that uses it.</p>
<pre><code style="color:black;"><span style="color:green;">#Show above an NPC</span>
class Talkbox_Window &lt; Window_Base
  <span style="color:green;">#npc is a GameEvent</span>
  def initialize(npc, txt)
    super(0, 0, 100, 50)
    self.z = 90

    <span style="color:green;">#Setup</span>
    self.contents.draw_text(0, 0, 100, 20, txt)

    <span style="color:green;">#Hide it</span>
    self.visible = false
  end

  <span style="color:green;">#We actually need to show the balloon a </span>
  <span style="color:green;">#  small amount offset above the npc</span>
  def update_pos(npc)
    self.x = npc.screen_x-47
    self.y = npc.screen_y-84
  end
end</code></pre>
<p>For the Event (NPC), have page 1 be autorun. Give it the following commands:</p>
<pre><code style="color:black;">Script:
  me = get_character(0)
  $myText = Talkbox_Window.new(me, "Howdy!")
  $myText.visible = true
  $myText.update_pos(me)
Set Switch 1: ON</code></pre>
<p>Give the Event a second page, and make the condition be “Switch 1 is ON”. Give it no commands.</p>
<p>Start the game and talk to the NPC. The box appears to work, but as you approach the NPC, you’ll notice an obvious flaw: the box scrolls with the map!</p>
<div id="attachment_19" class="wp-caption alignnone" style="width: 214px"><a href="http://lthzelda.files.wordpress.com/2009/02/post2_badly_scrolling_box.png"><img class="size-medium wp-image-19" title="post2_badly_scrolling_box" src="http://lthzelda.files.wordpress.com/2009/02/post2_badly_scrolling_box.png?w=204&#038;h=164" alt="Walking to our NPC causes his talkbox to scroll away." width="204" height="164" /></a><p class="wp-caption-text">Walking to our NPC causes his talkbox to scroll away.</p></div>
<p>A few interesting points, before we move on.</p>
<ul>
<li><code style="color:purple;">$game_interpreter.get_character(ID)</code> will return the event with the specified ID. If ID is -1, it returns the Player. If it is 0, the method returns the event which is currently being executed. Check the documentation for Game_Interpreter; there’s a lot of interesting stuff you can do!</li>
<li>Recall that by using a dollar sign for <code style="color:purple;">$myText</code>, we make it globally accessible.</li>
<li>If you try to call <code style="color:purple;">update_pos(me)</code> before you set <code style="color:purple;">$myText.visible</code> to true, the window will show, but (under some conditions) the text will not. It’s a bit of a quirk, but easy to handle if you know about it.</li>
</ul>
<p>Now, let’s fix up our program. The problem is, we’re using Windows in a way they weren’t designed for. Take a second and think: all other windows you see in the game are positioned statically at some point on the <em>screen </em>(not on the <em>map</em>, like NPCs are). This means we’re going to have to significantly alter the core coding of the game engine itself.</p>
<p><strong><em>Don’t Run Away!</em></strong> This isn’t nearly as hard as it sounds. Just make sure you’re reading twice as much as you’re writing. For example, start by opening the source for Game_Map and reading the function <strong>update</strong>. See how it calls <strong>update_scroll</strong>, <strong>update_events</strong>, and so on? Presumably, the second of these will update every event on the board. So after that, we can re-assign the x/y co-ordinates of our new text boxes. Add a new function call to <strong>update_talkboxes</strong> right before the call to <strong>@screen.update</strong>.</p>
<div id="attachment_21" class="wp-caption alignnone" style="width: 233px"><a href="http://lthzelda.files.wordpress.com/2009/02/post2_update_talkbox_position.png"><img class="size-medium wp-image-21" title="post2_update_talkbox_position" src="http://lthzelda.files.wordpress.com/2009/02/post2_update_talkbox_position.png?w=223&#038;h=184" alt="Where to insert a call to our custom update function" width="223" height="184" /></a><p class="wp-caption-text">Where to insert a call to our custom update function</p></div>
<p>Of course, now we have to define this function. Put it somewhere in the Game_Map file:</p>
<pre><code style="color:black;">def update_talkboxes
  if $myText
    me = @events[1]
    $myText.update_pos(me)
  end
end </code></pre>
<p>This code checks if <code style="color:purple;">$myText</code> exists, and then updates its position with that of event 1. You should only have one event on the map, so event 1 is guaranteed to be our NPC. Try it out.</p>
<div id="attachment_20" class="wp-caption alignnone" style="width: 209px"><a href="http://lthzelda.files.wordpress.com/2009/02/post2_manual_talkbox_working.png"><img class="size-medium wp-image-20" title="post2_manual_talkbox_working" src="http://lthzelda.files.wordpress.com/2009/02/post2_manual_talkbox_working.png?w=199&#038;h=160" alt="Our textbox now scrolls if we manually update it." width="199" height="160" /></a><p class="wp-caption-text">Our textbox now scrolls if we manually update it.</p></div>
<p>Congratulations, it works! But this was just a proof-of-concept; clearly you can’t make a global variable for each NPC you want to vocalize. Also, you need some way of directly attaching talk boxes to NPCs, so that our <strong>update_talkboxes</strong> code doesn’t get too bloated.</p>
<p>There are several options. You could just assign NPCs to talk boxes inside some RGSS “init” code, but this is tedious. Wouldn’t it be better if you could use the GUI itself to do it? My solution was to name a switch:</p>
<p><code style="color:black;">Switch 2 : FLAG! NPC Talkbox</code></p>
<p>Now, make an NPC with two pages:</p>
<p>Page 1 has as its condition that Switch 2 must be ON. Give it one command, a “Show Text” with some short message.</p>
<p>Page 2 has no conditions and no commands.</p>
<p>Now, find the source for <strong>setup(map_id)</strong> inside Game_Map. At the end of this function, add the following source:</p>
<pre><code style="color:black;">for event in @events.values
  event.init_npc_talkbox
end</code></pre>
<p>This will call a function (<strong>init_npc_talkbox</strong>) for each map event when the map first loads. Go into the source for Game_Event, and add the following attribute reader in the “Public Instance Variables” section:</p>
<p><code style="color:black;">attr_reader   :npc_talkbox</code></p>
<p>…and then add our new method:</p>
<pre><code style="color:black;">def init_npc_talkbox
  page = @event.pages[0]
  if page.condition.switch1_id ==2
    <span style="color:green;">#Steal the message box's text and init it</span>
    if page.list.size&gt;0 and page.list[0].code==101
      txt = page.list[1].parameters[0]
      @npc_talkbox = Talkbox_Window.new(self, txt)
      @npc_talkbox.visible = true
    end
  end
end</code></pre>
<p>This code is very elegant. It simply checks if page 1 of this event requires switch 2 to be on. If so, it takes the first line of text from the first event command (which should be a “Show Text” command) and initializes a talk box with that text. This approach might seem hackish, but it was designed for stability. It is now impossible to accidentally link a talk box to an NPC which doesn’t exist, or vice versa. Moreover, any event that happens to use switch 2 on page 1 (and also has a “Show Text” command as the first one) will be an easy glitch to detect —you’ll see an unexpected talkbox above the NPC.</p>
<p>There’s only one thing left to make this trick complete: let’s change our definition of update_talkboxes.</p>
<pre><code style="color:black;">def update_talkboxes
  for event in @events.values
    if (event.npc_talkbox)
      event.npc_talkbox.update_pos(event)
    end
  end
end</code></pre>
<p>Very concise. Here’s a screenshot of our demo in action.</p>
<div id="attachment_18" class="wp-caption alignnone" style="width: 201px"><a href="http://lthzelda.files.wordpress.com/2009/02/post2_auto_talkboxes_working.png"><img class="size-medium wp-image-18" title="post2_auto_talkboxes_working" src="http://lthzelda.files.wordpress.com/2009/02/post2_auto_talkboxes_working.png?w=191&#038;h=154" alt="Automatically scrolling talkboxes look snazzy!" width="191" height="154" /></a><p class="wp-caption-text">Automatically scrolling talkboxes look snazzy!</p></div>
<p><strong><em>Possible Improvements</em></strong>: This system is quite nascent; there’s a lot you can do to improve or expand it. Be creative! Here are just a few ideas to get you started:</p>
<ol>
<li>For some reason, the boxes “jitter” a bit when you walk up/down. This has to be an “off-by-one” error, since it fixes itself when you stop moving. Try to pinpoint this bug and fix it.</li>
<li>Talk boxes currently appear <em>immediately </em>after changing maps, which means they appear before the title screen has fully faded out. Find a solution for this.</li>
<li>Enhance talk boxes with Window_Message’s ability to detect symbols and color. (Start looking at <strong>convert_special_characters</strong>).</li>
<li>Enhance talk boxes with the ability to “open” and “close” like a normal window. For example, when you walk up to the person saying “Inn?” and hit Enter, their talk box should close and they should ask you if you want to pay 50G to sleep there.</li>
</ol>
<p><strong><em>Post-Posting Info:</em></strong></p>
<p>A certain fact has come to light since originally posting this tutorial. Please update your projects if you receive this error.</p>
<ul>
<li>Your “Talkbox_Window” module needs to be in a location that the interpreter can find. For example, add it below the “Windows” tab, or “Materials”. If you add it on its own to the end of the file, you might get an error when you try to run the program.</li>
</ul>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/lthzelda.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/lthzelda.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/lthzelda.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/lthzelda.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/lthzelda.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/lthzelda.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/lthzelda.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/lthzelda.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/lthzelda.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/lthzelda.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/lthzelda.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/lthzelda.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/lthzelda.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/lthzelda.wordpress.com/17/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=lthzelda.wordpress.com&amp;blog=6487794&amp;post=17&amp;subd=lthzelda&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://lthzelda.wordpress.com/2009/02/24/rm-2-speech-balloons-for-npcs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2d03df1949a14f50017efcdc0aacadcc?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">S&#039;orlok Reaves</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/02/post2_badly_scrolling_box.png?w=300" medium="image">
			<media:title type="html">post2_badly_scrolling_box</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/02/post2_update_talkbox_position.png?w=300" medium="image">
			<media:title type="html">post2_update_talkbox_position</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/02/post2_manual_talkbox_working.png?w=300" medium="image">
			<media:title type="html">post2_manual_talkbox_working</media:title>
		</media:content>

		<media:content url="http://lthzelda.files.wordpress.com/2009/02/post2_auto_talkboxes_working.png?w=300" medium="image">
			<media:title type="html">post2_auto_talkboxes_working</media:title>
		</media:content>
	</item>
	</channel>
</rss>
