Borderlands: Some highlights
At some point I may be ready to review Borderlands in it’s entirely. I’ve created 5 separate character files, tried all the classes, gotten above level 20 with three of them and finished a play-through with one. I’ve played online with two of my characters and sampled the splitscreen mode. To be perfectly honest, there remains alot of content to see and I still have the “omg I have to get home and play right now” feeling. This is after something beyond 40 hours of playtime. So I’m not gonna review the game, since I haven’t played the whole game and I’m still in love with it. Instead, here are some random thoughts from a gamer that’s still swooning…
Loot Love – There is a game play “feeling” being held hostage here. It’s the same thing that consistently drove me back to play World of Warcraft and with Diablo II gave me with a reason to avoid sleep. Fun, functional, unique weapons. Nothing beats the moment you equip that awe inspiring drop… except the first time you fire it!
User Driven Criticals – Critical strikes are becoming a commonality, especially in RPGs. Borderlands is no different, with weapons that confer +150% Critical Damage and skill points that improve it as well. The difference? Head Shot == Critical Hit. End of story. This has been a source of endless glee for me, and has motivated me to become a better shooter. Having all those extra stats behind you is a good motivator to aim rather than spray and pray. One last thing, every time that you get a critical hit, the word “Critical” pops out from the target in bold, red letters. Imagine if you will a point blank burst from a very accurate SMG. It’s like Christmas.
Charm – Borderlands has my favorite opening sequence in recent memory. It should be experienced in high definition and with the sound turned up. Watch it if you like. I’m obsessed with the two songs used in this game, Cage the Elephant – Ain’t No Rest For The Wicked and DJ Champion – No Heaven. They both have a feeling of untouchable badassery with a dose of pure fun that always gives me a few goosebumps. I could also start to comment on the art style, but any words spoken about it would not do it justice. It must be seen.
I just spent the last 20 minutes listening to the sound of the Bunker buster weapon digging through earth… stuck indefinately and on loop. It’s playing over my own custom soundtrack of the Dropkick Murphys. It hasn’t stopped. I have no answers to this, except turning off the Xbox. This feels a little like a busy city intersection.
ASP.NET’s Field validators are super useful, but one thing has always bothered me. By default when they don’t want the control to display it sets the style of the element to “visibility:hidden“. This is a problem most of the time, as the HTML element still occupies that space on the screen, it’s just invisible. My preference is for it to be “display:none” as it will no longer take up space in the DOM and other elements will flow into it’s place (ie. other required field validators).
<asp:RequiredFieldValidator ID="valFirstNameReq" runat="server" ControlToValidate="txbFirstName" SetFocusOnError="true" ErrorMessage="Please enter your first name." Display="Dynamic" ValidationGroup="cgstpForm" />
There it is. The property Display=”Dynamic” on a validation control switches it to this method. I found the naming of this to be non intuitive, since display set to dynamic makes sense now that i know it, but i never would have thought it had to do with this.
There’s a point where I get frustrated with myself as a programmer, and two particular issues come up often. Staying on task and keeping my skills sharp. Surprisingly, these two problems have the potential to solve each other. Below is the mad formula…
- Make a StumbleUpon profile for Programming – There’s a little itch that starts to bother you in the midst of productivity, the need to satisfy your content addiction. Indulge it. In fact, get the Firefox add-on so it’s right there at your fingertips. If you feel the urge, just click the button and read. Do it for a while (up to 5 minutes). Try to force yourself to digest what you see, really read it.
- Get Delicious – or another web-based bookmark sharing profile. Put everything cool you find here, and tag them relevantly. If you are loosing significant time (5 or more minutes) to any diversion, save it and come back later.
- Make a Twitter for Programming – block every invite and follow only relevant technical tweets from heavy hitters like Scott Gu and Rob Connery. If they link something (including stuff on their own blog) go take 5 minutes to read about it, even if it doesn’t make any sense to you.
I did these things. Given a little time, an open mind and a very very small dose of discipline I’ve discovered the following…
- You begin to devour content about your field. Heartwarming programmer jokes, experimental frameworks and practical tools/patterns all have the potential to enrich your skills and love for programming. It’s productive.
- You never get stuck in anything too long which fosters the ability to get back on task.
- You give more time than you normally would to ideas you would dismiss out of hand. This is always good. Worse case is that you will find valid reasons to dislike or dismiss it which gives you the ability to speak intelligently about the subject. Best case is you find something perfect that revolutionizes the way you do what you do everyday.
Like any method or practice the above is only useful if it produces results. I can say it’s increased my fascination with the craft and my desire to do more. See if it works for you!
Here are a few approaches if you’d like to have a customized pager control in multiple places on a page. Datagrid will do this for you, but if for whatever reason that doesn’t solve your problem this will get the job done!
Create a Pager control
Create a UserControl for your pager (mine is called Pagination.ascx). On the Page that will contain the pagination, register the Pagination UserControl and drop two of them on there.
Handling CurrentPage and PageSize values on the pager
The pagers will need two numbers to function; the current page of results, and records per page. The super duper easy way to save and load this state is to read the values from GET variables and store them as Parameters. You can go ahead and do this on the pagers themselves and you are done! When the value is changed via a dropdownlist for the PageSize or clicking to navigate to a new page, just Response.Redirect back to the same page with your values in GET (ie ?currentpage=1&pagesize=15). In fact if you have to get this done right away just go do that. It’s also worth noting that this makes it possible for users to bookmark searches (the below method does not).
The Event Driven Way: Handling the values on the containing element
As an alternative, lets say that you don’t wanna use GET variables and want to keep the info in a central location. When you first load the page, initialize the two variables and stuff the values into a serializable struct and save/load the control state of the page. Now the values are in one place and reliable.
Pass the values down to the child elements
Go ahead and write some code into the Pagination.ascx control to insert the values from the parent. To do this, you will need to create public Properties on the Pagination.ascx control in the codebehind file. Make a property for PageSize and CurrentPage as int. In the codebehind for your containing page, within the OnLoad method set these properties with your values like so…
cstTopPagination.PageSize = this.PageSize;
cstTopPagination.CurrentPage = this.CurrentPage;
cstBottomPagination.PageSize = this.PageSize;
cstBottomPagination.CurrentPage = this.CurrentPage;
So just before the pagers render, they will have the proper values and will be able to display as needed!
What to do when the pager changes
Here is where events come in. Even if you are pretty new to .NET you’ve likely utilized some events on Microsoft controls such as the DataGrid’s OnItemDataBound event or DropDownList’s OnSelectIndexChanged. We’re gonna make some of our own! Place the following lines into the codebehind for your Pagination UserControl…
public delegate void PageSizeChangedHandler(int PageSize);
public delegate void CurrentPageChangedHandler(int CurrentPage);
public event PageSizeChangedHandler PageSizeChanged;
public event CurrentPageChangedHandler CurrentPageChanged;
You can read more about how the above works, but in short the event serves as a method that you will call to signal ‘Hey, I’m changing the page size’. Any controls that link to this event will be notified, this is called Event Bubbling. The delegate is a contract with the controls consuming the event that tells them how they must create their methods to comply with the event. Think of it as a kind of interface.
Here is an example from Pagination.ascx.cs of how I call the event when a user clicks on a LinkButton with the CommandName of “Navigate” and a CommandArgument of a page number.
protected void CommandFilter(object sender, CommandEventArgs e)
{
switch (e.CommandName)
{
case "Navigate":
OnCurrentPageChanged(int.Parse(e.CommandArgument.ToString()));
break;
default:
break;
}}
Any controls that link into the Event CurrentPageChanged will be alerted with the value int.Parse(e.CommandArgument.ToString()). You’ll notice also that I call OnCurrentPageChanged not CurrentPageChanged. .NET creates this handle for you for your event.
On your containing page, you’ve probably got something similar to the following where your pagination control is on the page…
<rbl:Pagination ID="cstBottomPagination" runat="server" />
Modify it like so…
<rbl:Pagination ID="cstBottomPagination" runat="server" OnPageSizeChanged="PageSizeChanged" OnCurrentPageChanged="CurrentPageChanged" />
See how the events are accessible on the control? Now go to your codebehind for the page and add a method for PageSizeChanged…
protected void PageSizeChanged(int size)
{
this.PageSize = size;
this.CurrentPage = 1;
}
There you go. This officially completes the cycle; Value is loaded in the containing page, passed down to child, if it changes it is bubbled back, and the value is saved on the containing page at the end. This method also works if you have a UserControl within a UserControl and you’d like to bubble the event up.
There’s lots of practical and creative uses for events. This implementation is simple but it was fairly easy to learn and has potential for very powerful and smart controls. It cuts down on ‘black magic’ in your child controls where information is obtained circumstantialy or through unpredicatble traversal. Events are clean and readable once you understand them, and I like them alot.
I ran into an interesting roadblock trying to set up this very blog. I wanted to take the out-of-the-box WordPress installation and throw it on a managed hosting solution, no biggy.
I installed Apache 2.2.13 and MySql locally and was able to simulate the entire install perfectly. On the web server this did not work, I was greated with a friendly (but completely unusful) custom 500 error with no description.
A quick Google search lead to this forum thread which revealed a solution for viewing the true 500 error on an IIS 7.0 managed hosting solution, which involves dropping a web.config file in the site root with the following code…
<configuration>
<system.webServer>
<httpErrors errorMode="Detailed"/>
</system.webServer>
</configuration>
This is of course a no brainer for those used to creating .NET web applications, but it was funny to see this in a site that was running no .NET code at all (WordPress is PHP). Oddly enough, this completely fixed my problem. The custom 500 error went away and my super easy to use WordPress setup page appeared. I’d like to look into why changing the error mode ‘fixed’ stuff, but I can live with the black magic for now.
As an exercise for myself and inspiration, I downloaded a swath of indie games from the XBLA. One of the first ones I chose was I MAED A GAM3 W1TH Z0MB1ES!!!1. This was because it’s came up first in the ‘Most Downloaded Category’ or indie games. Yes yes, perhaps I should ‘gone digging’ and looked for something more under appreciated. I will be sure to make up for my sins later. Anywho…
Buy this game. Here are a few reasons:
- It’s 1$
- It’s charming. It has a theme song. It pokes fun at itself.
- The game mechanic is fun and mesmerizing.
- It’s crazy, which is part of the fun of indies games, and that should be encouraged.
It’s also worth mentioning that within the last few months since the inception of the new XBL Experience, a plethora of purchasable content has arrived in the Avatar Marketplace. I really must say that while I am probably enough of a fan of Penny Arcade to buy this shirt, I couldn’t rightfully do so until I bought this game. Do both! Stimulate the economy! Here’s some things you could give up to save a buck for this game…
- Take that jar of pennies you keep around and take it to Coinstar
- Order a water with your meal at Applebees
- Go to a local coffee shop instead of Starbucks one day (this will save $2 sometimes)
And you’ve supported a cool indie game. Now go blow up some Z0MB1ES!!!1