Thursday, January 17, 2008

Descriptive Words

The blog will be what I can best describe as "wonky" until I get it all moved over to Zero Altitude.  In the meantime, take solace in the fact that I've got tons of good music here to keep me moving until I finish putting everything up.

Things to do while idling on the tarmac

There probably was a pilot or two and a very friendly sounding controller at Van Nuys who saw me sitting around in a Baron 58 at LAX and abroad today on VATSIM.  What I was doing was testing the module version of Squawkbox 4, meaning the version you launch from inside of Flight Sim.  The good news is that me sitting there on the network meant that it worked.  It's a real milestone in the project for me, and while there is plenty of work to do moving forward, we are reaching a point where we can get beta testers running it, and that brings us closer to release.

I know Joel and I both take the development of Squawkbox very seriously.  It's quality is not representative of a company or a group or anything like that, but us personally, and I am doing everything I can to live up to the high standard he's set. 

Joel and I will be getting together online in the near future to talk about the plans as we continue forward towards release.

Recently, Phil Taylor has been posting about some great job opportunities at ACES.  If any of you are programmers, I'd take a look at it.  When you meet these guys in person, you really understand their passion for creating the sim we love.  If you head over to http://www.microsoft.com/careers and do a search with the term "Flight Sim" in double quotes as the keyword, you should find all of the related jobs.

If you want to go start your own company, GamesIndustry.biz put up a very interesting piece on why it's so awesome to have a game studio in Canada.  I guess they just give you money or something.

Tuesday, January 15, 2008

Connect Three Red Cubes to Fire Phasers

Ok, so I've been pushing for a long time, a very long time, for someone to make a MMO where it's a bunch of people on a spaceship traveling around galaxies and doing adventure-type stuff.  Firefly/Lost In Space/MMO X3, whatever. It appeared that we might get that in the new Star Trek Online, until developer Perpetual Entertainment decided to push into the super-profitable casual market, taking STOnline with it. When screens appeared recently, it had a much softer, cartoony look to it, far from the ultra-realistic renders of early concept work.

It looked like a casual game.

Now, just the other day, I was promoting the concept of Puzzle Pirates in Space to Will, and in hindsight, I realize this is exactly what it was becoming.

So it gives me some relief today to read the news the Perpetual, or P2 or whatever it's called now has been pulled from the development of Star Trek Online, and an unnamed developer will be taking over, and more than likely, starting over. This probably means it will be years before we see an actual game out of this, leaving the Firefly MMO that FOX is making as the nearest hope. And let's face it, it's not going to be good at all.

Here's what we were told it would look like originally during "Look Development":

Click here for the big version of what they made it look like.

All of that development and look, all of those hardcore trek fans designing layouts of ship interiors and getting Mike Friggin' Okuda as a consultant on the panel design and it just feels like somewhere along the way, the business end of things said "Think WoW in space!" and that's where it went.

I expressed some sympathy earlier because those guys really seemed to be hardcore about this, but I'm glad I'm the powers that be at Perpetual were not allowed to take the game in the direction they were going, and I hope the new parties responsible will try to succeed in the original vision of the game.

Or dammit, I'm just going to have to do it myself.

Monday, January 14, 2008

What Is Happening?

It turns out, I'm very busy.

I am going to be making a status update to Joel and the VATSIM guys on the progress of SB4, but thanks to some job-hunt stuff that came up today, that probably won't happen until tomorrow.

I'm building TrackerX into my new website, and it hopefully shouldn't take all that long to transfer over.  I'd like to explore Silverlight and Live maps as a good alternative to my straight Javascript/Google Maps implementation now, but we'll have to see how much time that will cost me.

The website is proceeding slowly, since I don't have as much time to work on it, but I do have the blog up for the most part over there.  You can view that here.  I'll be putting up new content as it becomes stable in my testbed.  If you run into any troubles with it, let me know.  It should be noted that permalinks to the posts, comment page links, and any links from blogger still come to the NotASenator.com page.  I'll be fixing that as I migrate from blogger to my own solution.

The video tutorial was well-received and I look forward to making more.  It's actually a bit easier for me, and I feel that it offers a better direct explanation of the things I would want to explain.

Hitting the gym tonight, it's been rough on my body to get back into my routine.  We'll all know in a day or two whether I was able to take it easy or not.

Saturday, January 12, 2008

Menus and Modules, a Video Tutorial

I've put together something of a "test case", creating a video capture of my desktop activity while I create and explain a simple SimConnect application to place menus and text into FSX.

The sound quality is terrible, and that's something I'm getting some professional advice about fixing, however, except for some pops, I don't think it's too unbearable.

Feel free to download the file here (right click and save as, approx. 64MB) or simply watch the smaller version embedded below:

 

This is my first go at something like this, please leave questions and comments for me.

UPDATE: I wanted to mention that José Oliveira gets the credit for this simpler method of not showing the window.  Thanks, JC.

Friday, January 11, 2008

The Oldest Review Possible

I'm working like mad on SB4 and the new website, but I did take a little time to go to a game night at a friend's house.  While Call of Duty 4 on the 360 gave us some high-paced next-gen competitive play, we soon pulled out Ghost Recon Advanced Warfighter and played four player co-op split screen.  Realistically, the old GRAW should not be out-doing the award winning brand-new C0D4, but there was a decision along the way to make co-op over Live only.  This meant that the four of us sitting in a room with one TV could only shoot each other and do nothing else.

GRAW, on the other hand, had us wandering though crazy levels hunting down tangos together, the tension and excitement was shared and that can't be topped by shiny graphics.

So the discussion became "hey, they made a new one, you know".  We are talking about getting GRAW2 for increased Tango-Downing, and with that in mind, here is the five star Gamespy review from that game:

http://xbox360.gamespy.com/xbox-360/tom-clancys-ghost-recon-advanced-warfighter-2/771436p1.html

Wednesday, January 9, 2008

New Host Inbound

I rewrote my WoW chat program in ASP.NET to demo on the web, but found that Dreamhost doesn't support ASP at all.

So I'm looking at other opportunities, perhaps Reliable Web Hosting since they are cheap, look good and I like their website.

Anyone here using a host that supports ASP.NET 3.5?

Monday, January 7, 2008

Watch this space

Feeling a little under the weather but I will have this post up tomorrow morning.

Sorry for the delay

Sunday, January 6, 2008

WoW Chat Project Part 2

So let's jump right in.  We've got the program starting and running fine, and setting the proper channel.  Now we have to handle the event that fires when the user presses "Enter".  We want to write the text of the entry window to the chat window, clear the entry window and set the channel back.

To get us started, we want to add an event handler to the Form1 constructor:

public Form1()
{
InitializeComponent();

rChatEntry.KeyDown += new KeyEventHandler(chatEnterPressed);
}

I covered event handlers in the SimConnect tutorials, but the whole handler/delegate concept is pretty simple.  When something happens in specified control (in this case, that's the chat entry window, rChatEntry) it fires off an event.  Since we've registered an event handler, the event has a delegate, which is simply a function that runs when the event gets fired.


So now we need chatEnterPressed.

private void chatEnterPressed(object sender, KeyEventArgs e)
{
// check to see if Enter was pressed
if (e.KeyValue == 13)
{
if (rChatEntry.Text.Length != lineStart)
{
}

e.Handled = true;
}
}

This is essentially just the frame, we'll get to the guts of the function in a second.


An event handler function like this has parameters for the sender which is simply whatever control or object sent the event.  The variable e represents whatever arguments got sent along with the event, in this case, it's info about the keypress.   For example, we are testing here for a specific key value, 13, which is the Enter button. 


Then we throw in a little validation to make sure the length of our total string (channel name + user input) is not the same as our lineStart value.  You may recall, lineStart is our "real" starting position, meaning how far along the chat entry text string where user input starts.  So if the values are the same, there's been no user input.  We don't want to send empty lines to the chat, so we have that check in there.


The last little bit is e.Handled = true.   When we get an event like a keypress, the event handler's delegate gets called, but there is still a default handling of the keypress.   In the case of the textbox like we are dealing with it's just a new line, but we don't want that.  We want to go back to the start of the first line.  So we say that the event is "Handled" so that any other event handlers don't touch it.


Now for the guts:

if (lineStart != rChatEntry.Text.Length)
{
// add the line to the chat window
rChatWindow.SelectedRtf = rChatEntry.Rtf;

// clear the text entry
rChatEntry.Select(0, rChatEntry.Text.Length);
rChatEntry.SelectionProtected = false;
rChatEntry.Text = System.String.Empty;

// Set the channel back
chatSetChannel(selectedChannel, selectedColor);

// Scroll to the proper point
rChatWindow.ScrollToCaret();
}

rChatWindow.SelectedRtf  is the spot in the chat window where our cursor/caret/pointer whatever you want to call it is.  We've used the Text property to get the contents of textboxs, but with Rich Text, we can copy the formatting over as well.


Then we select everything in the chat window, set it to unprotected, and empty the string out.  Now we should have a blank chat entry field, and the line of chat is in the chat window.  


Back to our handy helper function to set the Channel name in the entry box.  The last little bit is a textbox function that scrolls the window (if necessary) to the position of the caret.  In this case, what it means is that if the text in the window gets long enough to cause a vertical scroll bar to appear, the window scrolls down to show whatever new line is added.


autochannel4


Looks like that is working fine. 


Now for the real point of this all, the channel switching. 


The real simple way to assign an event handler for the TextChanged property is just going into the designer view and double clicking on our chat entry bar.


It should create the function for you.  I renamed the generated function to chatTextChanged to fit with everything else.  There are some good tools in here for renaming or refactoring.  By clicking on the little red underline that appears or by pressing Shift-Alt-F10, you get the rename dialog, and can select to rename the function.  This is important because there's an event handler auto-generated that assigns the new function as a delegate.  If we change the name of the function without updating the event handler through the rename dialog, we end up with errors and general not-working-ness.


This event will fire whenever there's a change to the text in the entry window.  We'll then check to see if the text is two characters longer than our lineStart value, for the "/g" or whatever we need.  If so, the next step is to select just those two characters, set it to lower case for matching purposes and match it to a list of possible solutions.  If it doesn't match any of them, just deselect it all.


The rest is simple, because we've already got a helper function to set the channel.


So here's our code to do it.

private void chatTextChanged(object sender, EventArgs e)
{
// test if the first two characters are /something. If there are more than two characters, skip it

if (rChatEntry.Text.Length == lineStart + 2)
{

// use a switch to test for our cases
rChatEntry.Select(rChatEntry.Text.Length - 2, rChatEntry.Text.Length);

switch (rChatEntry.SelectedText.ToLower())
{
case "/g":
// Switch to guild chat
chatSetChannel("Guild", Color.Green);
break;

case "/1":
// Switch to general chat
chatSetChannel("General", Color.Black);
break;

case "/2":
// Switch to trade channel
chatSetChannel("Trade", Color.Orange);
break;

case "/s":
// switch back to local "saying"
chatSetChannel("Say", Color.Red);
break;

default:
// deselect all
rChatEntry.Select(rChatEntry.Text.Length, rChatEntry.Text.Length);
break;
}
}
}

 


Walking through it, we have the test to check if we only have two user-inputted characters, selecting those two characters, and then a switch statement to test for the various slash commands we are looking for.  Notice in the switch line that we use the ToLower method so that "/G" comes out the same as "/g".


Then for each case, we set the channel using our helper program, and if it doesn't match anything, we deselect our selection.


autochannel5


Looks like it works fine.  I added in functions for the context menu items and a little mouse click handler that keeps the user from changing our position in the chat window.  Otherwise, it could be possible to insert chat lines in the middle of other lines. 


Here's the code as I have it:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace AutoChatChannels
{
public partial class Form1 : Form
{
// The currently selected channel
private string selectedChannel = "General";
private Color selectedColor = Color.Black;

// Since we are appending a channel name to the beginning of the line, we need to keep our own count
// where the "real" line (i.e. the user input) starts
private int lineStart = 0;

public Form1()
{
InitializeComponent();

rChatEntry.KeyDown += new KeyEventHandler(chatEnterPressed);
rChatWindow.MouseDown += new MouseEventHandler(rChatWindow_MouseClick);
}

void rChatWindow_MouseClick(object sender, MouseEventArgs e)
{

rChatWindow.Select(rChatWindow.Text.Length, rChatWindow.Text.Length);
}

private void Form1_Load(object sender, EventArgs e)
{
// Get datetime of entry into the channel
string currentDate = DateTime.Now.ToString();
// Write out the join message
string entryText = "You have joined the General Chat Channel at "+currentDate+System.Environment.NewLine;
// Add the text to the chat window
rChatWindow.Text += entryText;


// Now we have to select the text to make formatting changes to it.
rChatWindow.Select(lineStart, entryText.Length);

// make the text blue and bold
rChatWindow.SelectionColor = Color.Blue;

// Now make sure nothing is selected
rChatWindow.Select(rChatWindow.Text.Length, rChatWindow.Text.Length);

// Enter that in our text entry box
chatSetChannel(selectedChannel, selectedColor);
}

private void chatTextChanged(object sender, EventArgs e)
{
// test if the first two characters are /something. If there are more than two characters, skip it

if (rChatEntry.Text.Length == lineStart + 2)
{

// use a switch to test for our cases
rChatEntry.Select(rChatEntry.Text.Length - 2, rChatEntry.Text.Length);

switch (rChatEntry.SelectedText.ToLower())
{
case "/g":
// Switch to guild chat
chatSetChannel("Guild", Color.Green);
break;

case "/1":
// Switch to general chat
chatSetChannel("General", Color.Black);
break;

case "/2":
// Switch to trade channel
chatSetChannel("Trade", Color.Orange);
break;

case "/s":
// switch back to local "saying"
chatSetChannel("Say", Color.Red);
break;

default:
// deselect all
rChatEntry.Select(rChatEntry.Text.Length, rChatEntry.Text.Length);
break;
}
}
}

private void chatSetChannel(string channelName, Color channelColor)
{
// Select everything
rChatEntry.Select(0, rChatEntry.Text.Length);

// Unprotect everything first
rChatEntry.SelectionProtected = false;

// Set channel name
rChatEntry.Text = "<" + channelName + "> ";

// Select the text again
rChatEntry.Select(0, rChatEntry.Text.Length);

// Set the color
rChatEntry.SelectionColor = channelColor;

// Set the current text as protected
rChatEntry.SelectionProtected = true;

// Clear the selection to the end of the channel name
rChatEntry.Select(rChatEntry.Text.Length, rChatEntry.Text.Length);

// set our "real" start of line position
lineStart = rChatEntry.Text.Length;

// set our color
rChatEntry.ForeColor = channelColor;

// Selected Channel/Color
selectedChannel = channelName;
selectedColor = channelColor;
}

private void chatEnterPressed(object sender, KeyEventArgs e)
{
// check to see if Enter was pressed
if (e.KeyValue == 13)
{
if (lineStart != rChatEntry.Text.Length)
{
// add the line to the chat window
rChatWindow.SelectedRtf = rChatEntry.Rtf;

// clear the text entry
rChatEntry.Select(0, rChatEntry.Text.Length);
rChatEntry.SelectionProtected = false;
rChatEntry.Text = System.String.Empty;

// Set the channel back
chatSetChannel(selectedChannel, selectedColor);

// Scroll to the proper point
rChatWindow.ScrollToCaret();
}

e.Handled = true;
}
}

private void menuitemGeneralChannel_Click(object sender, EventArgs e)
{
chatSetChannel("General", Color.Black);
}

private void menuitemTradeChannel_Click(object sender, EventArgs e)
{
chatSetChannel("Trade", Color.Orange);
}

private void menuitemGuildChannel_Click(object sender, EventArgs e)
{
chatSetChannel("Guild", Color.Green);
}
}
}

 


Pretty simple little process all in all, I'd like to build off of it down the road, maybe incorporate it into something.


Please feel free to drop any questions in there for me.

Labels: , ,

Saturday, January 5, 2008

WoWing a Small Chat Project

One of the goals of the new programming focus this year was to try a variety of small projects,  small exercises to stimulate the brain and increase my programming agility.  There's no shortage of things to try, so I consider this a warm-up of sorts.

If any of you have played World of Warcraft, you'll get the idea pretty quickly, for everyone else, in WoW, there is a chat box that allows you to talk to everyone else in the game world.  To make this as efficient as possible (theoretically), the chat is split into channels.  You can use a menu to select what channel you are talking to, or just type "slash commands" which is a forward slash (/) followed by a letter or number to indicate the channel you want.  When you do this, the slash command gets replaced with the name of the channel.   The goal of this project is to emulate that.

I figure that this project presents a few challenges.  First off, finding the most effective way of detecting the entry of a slash command.  Once we get the channel name in there, it's part of the text string, so we want to have a way of pushing what we consider the "start" of the entered text.  Once we get lines of chat added, we want the chat window to keep our place when new lines are added.  So we've got a few things to tackle.

Stage One: Planning -

The way I figure, the best way to go about this is to have a pair of richTextBoxes (which can do the necessary formatting easily), one for the chat entry, one for the chat window displaying the already entered lines of text.  There would also be a menu detached from the top of the window that will be the alternate method of changing channels.

Here's the naming conventions I use:

Chat Entry window - rChatEntry
Chat display window - rChatWindow
Channel Selection window - menuChannelSelector

And here's what it looks like in designer:

autochannel1

Not the most complicated design ever.  The "Channel --->" part is the Menu, don't feel that you need to add it yet.

A few things to note:

- both text boxes are multiline = true, the bottom window (rChatWindow) is read-only and scrollbars = vertical.   rChatEntry has it's tab index set to 0 (zero) so that's the first thing that gets input focus on loading.
- I toyed with disabling rChatWindow completely, but learned quickly that then you couldn't scroll back up.  This ended up presenting it's own issues later on.
- I'm using Visual Studio 2008 Professional on Vista Home Premium, Aero turned off for that little bit of extra juice, just in case your view looks different.  Oh, and big one, I believe this is built for .NET 3.5.

I'll get to the context menu later.

Continuing the planning, let's lay out the structure of what's going to be happening here:

We're basically working completely off of events here, so we have a few functions to handle these events:
- chatTextChanged,  called whenever a change is made to the text of rChatEntry.  Previously, this could be handled by detecting a keypress, but this is the preferred way of going about it.  This function will see if we've entered a slash command and handle it properly.
- chatEnterPressed, called whenever you hit the enter key on your keyboard.  While our chat entry line will wrap if you go past the end of the line, we want "enter" keypresses to send the line to the chat window.

In addition to this, we'll have some initial stuff happening on the loading of Form1 (I left the default name there) and a helper function called chatSetChannel that does the repetitive work of changing the channel.

 

So, let's get started.

public Form1()
{
InitializeComponent();

}

In our Form1 constructor, we've got some stuff to add later, but for now we are fine.


Right above that, let's get some of the needed variables in there:

// The currently selected channel
private string selectedChannel = "General";
private Color selectedColor = Color.Black;

These are to keep track of what channel we are on and what color is associated with it.  Thanks to .NET, we don't have to do much with the colors, there are plenty predefined.


Now, when the form loads, we want to put a message in the chat window that we've joined the General channel at this date and time, and get our entry box set up on the correct channel.  I like doing this in the OnLoad event, because it keeps it clean and separated from the constructor and it also makes sure everything is actually set and loaded before I go screwing around with it.  I don't really think that would be a problem, but I do it anyways.

private void Form1_Load(object sender, EventArgs e)
{
// Get datetime of entry into the channel
string currentDate = DateTime.Now.ToString();
// Write out the join message
string entryText = "You have joined the General Chat Channel at "+currentDate+System.Environment.NewLine;
// Add the text to the chat window
rChatWindow.Text += entryText;
}

In this first part, we're using .NET to get the current time, slapping it in a string and putting it in the chat window.  Piece of cake.  Run the code to give it a try and we should see this:


autochannel2


Outstanding.  There is, however, a reason why we used richTextBoxes instead of just normal textboxes, and that's formatting.  Programmatically, it works almost the same as it does through a UI.  You select the text you want to edit and apply the formatting to that selection.


In our case, we want to select the text and make it blue.


Right after that last bit of code:

// Now we have to select the text to make formatting changes to it.
rChatWindow.Select(0, entryText.Length);

// make the text blue and bold
rChatWindow.SelectionColor = Color.Blue;

The Select method on a richTextBox sets the range of text to be selected, in this case, from 0 (the beginning) to the end of the string.  Then we simply set the color of the selection with SelectionColor.  As I said earlier, the .NET framework helps with the colors.


If we run it now, we should probably see blue text.  What's interesting is that you could change a few things so that your input focus starts in rChatWindow and you'd see that at this point, the text would actually be highlighted in the box, as if you had selected it with a mouse.  We want to take care of that, and we do so with this:

// Now make sure nothing is selected
rChatWindow.Select(rChatWindow.Text.Length, rChatWindow.Text.Length);

The syntax is "Select (StartIndex, EndIndex)"  so why not make it (0,0)?  Well, the select function is more like a mouse than we even saw before, it places the caret, or flashing cursor, our position in the textbox at the point at the end of the selection.  So by using the Length property of the textbox, we are setting the cursor to the end, so we can append more lines on to the chat window without trouble.


The other thing we want to do is set our chat entry box to represent the current channel, which starts on
"General".  It's here where we get to explore some of the issues presented to us.  Turns out, most of them are easy to solve.  A quick rundown:  The textbox shows the name of the active channel in front of whatever you type, i.e. "<General> Here is your message".  We have to insert that channel tag and make sure the user can't alter it.  In addition to that, if the user types "/g" or another slash command as the first characters in the box, we need to change that "<General>" to the new active channel and color. 


To solve the issue, we need to know what the "real" starting point of the user inputted string is.  We're going to be sticking our own text in the beginning of the string, so we need a count of how much we've added.  This will give us an index pointing to where the user's entry began.  To do this, we're going back to the top where we've declared our variables and we're going to add an integer called lineStart.   This should reasonably tell us where to start our selections when searching user input.

// The currently selected channel
private string selectedChannel = "General";
private Color selectedColor = Color.Black;

// Since we are appending a channel name to the beginning of the line, we need to keep our own count
// where the "real" line (i.e. the user input) starts
private int lineStart = 0;

We initialize it to zero.  Now, for the sake of completeness, we could go back into our Form1_Load and replace the "0" in our select call with lineStart.


Now that we've knocked that out, we start building our chatSetChannel helper function.  We're going to be changing the channel name a few times in here, so we don't want to repeat the same code.

private void chatSetChannel(string channelName, Color channelColor)
{
// Select everything
rChatEntry.Select(0, rChatEntry.Text.Length);

// Unprotect everything first
rChatEntry.SelectionProtected = false;
}

These first two methods get us started with some validation.  Before anything else, we select the whole text box and make it unprotected.  Protected text can't be altered.  This is one of the benefits of richTextBoxes, and it's how we plan on keeping the user from messing with our channel name.


The rest of this is pretty straightforward.

// Set channel name
rChatEntry.Text = "<" + channelName + "> ";

// Select the text again
rChatEntry.Select(0, rChatEntry.Text.Length);

// Set the color
rChatEntry.SelectionColor = channelColor;

// Set the current text as protected
rChatEntry.SelectionProtected = true;

// Clear the selection to the end of the channel name
rChatEntry.Select(rChatEntry.Text.Length, rChatEntry.Text.Length);

We format the channel name in brackets and slap it in the text box.  Now that our text is longer, we select the whole thing again, and use the SelectionColor property to make it all whatever the channel color is.  Not very exciting, but the General channel is black, as we set at the beginning.  With this section selected, we protect it, locking it from changes.  This will protect anything entered in after the selection until we make a new selection, so we move our selection to the end, ready for user input.

// set our "real" start of line position
lineStart = rChatEntry.Text.Length;

// set our color
rChatEntry.ForeColor = channelColor;

// Selected Channel/Color
selectedChannel = channelName;
selectedColor = channelColor;

Now, some housekeeping, we update the lineStart variable to indicate where the user input begins in rChatEntry and make the foreground (which means the text, in this case) color to our channel color.  This is so whatever the user types is the same color as the channel name.  Wrapping it up, we set our channel tracking variables to the values of the current channel.  That doesn't change right now, but it will when we are actually switching channels.


 


All of which will come tomorrow as it is very late right now.    Here's the code so far:


 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace AutoChatChannels
{
public partial class Form1 : Form
{
// The currently selected channel
private string selectedChannel = "General";
private Color selectedColor = Color.Black;

// Since we are appending a channel name to the beginning of the line, we need to keep our own count
// where the "real" line (i.e. the user input) starts
private int lineStart = 0;

public Form1()
{
InitializeComponent();
}
        private void Form1_Load(object sender, EventArgs e)
{
// Get datetime of entry into the channel
string currentDate = DateTime.Now.ToString();
// Write out the join message
string entryText = "You have joined the General Chat Channel at "+currentDate+System.Environment.NewLine;
// Add the text to the chat window
rChatWindow.Text += entryText;


// Now we have to select the text to make formatting changes to it.
rChatWindow.Select(lineStart, entryText.Length);

// make the text blue and bold
rChatWindow.SelectionColor = Color.Blue;

// Now make sure nothing is selected
rChatWindow.Select(rChatWindow.Text.Length, rChatWindow.Text.Length);

// Enter that in our text entry box
chatSetChannel(selectedChannel, selectedColor);
}

private void chatSetChannel(string channelName, Color channelColor)
{
// Select everything
rChatEntry.Select(0, rChatEntry.Text.Length);

// Unprotect everything first
rChatEntry.SelectionProtected = false;

// Set channel name
rChatEntry.Text = "<" + channelName + "> ";

// Select the text again
rChatEntry.Select(0, rChatEntry.Text.Length);

// Set the color
rChatEntry.SelectionColor = channelColor;

// Set the current text as protected
rChatEntry.SelectionProtected = true;

// Clear the selection to the end of the channel name
rChatEntry.Select(rChatEntry.Text.Length, rChatEntry.Text.Length);

// set our "real" start of line position
lineStart = rChatEntry.Text.Length;

// set our color
rChatEntry.ForeColor = channelColor;

// Selected Channel/Color
selectedChannel = channelName;
selectedColor = channelColor;
}
}
}

When I give it a shot, I get this:


autochannel3


Next I'll be making chat entry actually enter chat into the chat window and allow for the changing of colors.

Labels: ,

Friday, January 4, 2008

The Trouble With Excitement is...

...that we don't always double check things. I was very happy to see Visual Studio appear in my mail the day after I was reading about the code metrics tools in 2008, and neglected to notice that these features were available in the Team Suite, while I had been sent the normal old Professional version. As of right now, Team Suite only seems available to me as a 90-day trial, so I'll probably get that later on to give it a shot.

The lesson is: when dealing with multiple product versions, always check the fine print. As it is, VS2008 looks like a healthy and stable upgrade, so I'm looking forward to poking around in there.

This doesn't count as my daily post, I've got more to talk about later on.

Labels: ,

Thursday, January 3, 2008

One Small Step

Leanna is writing the first of many "Honey-Do" lists for me, little errands for me to run tomorrow. Not on the list, but certainly something I'd like to accomplish tomorrow is installing Visual Studio 2008. They sent me beta invites, put it up through the MSDN subscription and now sent it to me on DVD in the quarterly package that arrived today. I think I owe it to them after all the trouble to install and see what all the fuss is about.

One of the things I'm really excited about is code metrics. I'm always interested, not coming from a formal training background, to see how my work ranks up. The new code analysis tools show maintainability and complexity of code parts. There's a good overview here. Watching a video on the Microsoft site, I'm seeing a lot of code optimization work going into it. For example, I will from time to time have parameters in functions that I might need in testing but forget to remove in a shipped project, and Code Analysis will apparently find all of this and take care of it.

We'll see how it goes. Anyone using VS2008 already?

Wednesday, January 2, 2008

Designer Jeans?

I was challenged today to make a post about designer jeans, and relate it to programming, which is somewhat daunting.

I ventured into the SB forums and was a bit surprised to see the posts I found there. I guess everyone is not as aware of the absolute volume of work put into this program and its ancillaries, a project reaching almost 100,000 lines of code, and maintained by one man. Daunting to take over, daunting to step into the light of expectation from the current userbase of SB3.

Of course, Joel has done most of the work. As he's mentioned before, the program is, for the most part, done. Portions have been in testing with a beta team, and a good amount of the core development has been checked off.

So what's the delay? Well, for starters, what has been said on the forum is true. I am coming in dark to this all. There is an awful lot to learn, and I've been taking it all in as fast as possible. I am in no way starting over, and the project is not getting abandoned. For those of you who don't use SB, there are several "code trees" at work here. There are internal (module) and external (exe) versions, both of these working on either FSUIPC or SimConnect, and the FSUIPC versions having elements for FS8 and FS9, which continue to be supported. Most of this is done. Let me clarify ahead of time what I mean by "done", and that is: the program elements are working in test situations. This is not the same done as in "If it's done, why not package up what you have and release it while you keep working on new stuff?" done. It's not there, and I don't think Joel or I would want to put that sort of statement of quality on our work anyways.

So what's left is that I'm now writing the module portion for FSX, and progressing along nicely. Once that is done, which includes loading the module at launch, establishing a connection through SimConnect, activating the menu item in the sim and handling the loading of the internal program window when you use said menu item, then there is the matter of testing all of it, which I believe Joel already has a good mechanism in place for, as well as going through the whole codebase and updating everything to the latest version specs, cleaning stuff up, some more testing, some more cleaning, packaging it up and getting it on its merry way.

Really, I would have loved to have had something for Christmas or New Years, but I had to selfishly go and get engaged.

But Joel and I have talked a lot about this and I'm in it for the long-haul. I'm very excited to see where SB and Flight Sim go after this version.

So much for combining this with designer jeans.

Labels: , ,

Tuesday, January 1, 2008

New Years Resolutions

A few things of great importance:

A few days ago, right before Christmas, I asked my girlfriend Leanna to marry me and she said yes. We haven't set a date, but I don't think I've ever been happier.

Between that and the holidays, I haven't been terribly available. I have, however, been working on progressing the SB4 code. For a while, it was all about finding my way through the code. I've moved on to working specifically on the module section of the program, that is, the part that opens internally in FSX. It's going well so far and I hope to be able to review the progress with Joel soon.

I'm not one for New Years' Resolutions, but I want to be able to look back at my progression as a programmer this year, so I'm going to try doing some coding everyday and blogging every day as well. This should give me the propulsion to get some use out of this webspace.


Happy New Years and watch this space.