Coding Updates

Over the past months, I’ve submitted a few changes to Towny.

  • (Old News) If you didn’t know, I’ve added a new war mode. It’s different than the previous one where the admin would trigger an event and the entire world is at war. This version will take your alliance (enemy / allied) into effect, and allow you to capture your enemy’s plots.
  • A more recent change to it is that I’ve added economic costs for attacks in the new war mode.
  • A smoke effect around the border of a plot do help distinguish the boundaries of a plot better. This should lead into a few optional modules to build a fence around plots, etc later.

I’ve done more tinkering outside of Bukkit though.

  • Created a custom theme for the Quassel IRC client. It’s simple CSS based on the Monkai theme you see in a lot of places. You can check it out here.
  • Learned a few python tricks and tried out the Google App Engine through Udacity‘s CS235 free online class.

New Project: QuestBuilder

I realized my entire design for Quest Editor was flawed. While NPC data is mostly consumed of checkmarked options and a ComboBox, Quest data has an insanely complicated hierarchy. My experience with extending Java’s native GUI components is slightly better after my first attack, but I know that making 20 slightly similar classes along with a fair amount of custom panels and comboboxes (item/npc/quest selection). The worst would be the text editing. The entire point of the GUI was to make things simplier than formatting YAML markup. Which I realized wouldn’t be the case.

The best method would actually be to create a script alongside a parser that would build the YAML markup. After 5 hours of hacking and slashing, I’ve gotten it working. A fair amount of time was spent updating Citizen’s own save functions for quests.yml.

Here’s an example of the script, and it’s output.

===
New Players
Rift

NPC guardian
===

The Rift is a seperate entity outside of time and space. Here generations before you have made it simple to go to any slot in time you wish. The portal behind me will take you to Eldaria in the year 1600 AD.

To open a portal, throw the lever beside it, but be sure to quick and step through before the portal closes!

Some portal can take you to multiple places, to chose one, click the panel beside the lever till the desired target is selected.

Now step forth and try it. Then witness with your very eyes, the fall of Eldaria.

* The guardian hands you a book for you to pen your adventure. Then lightly shoves you towards the portal.
ITEM book

===
Go Kill Zombie
Eldaria
1600 AD

NPC alex
===

Ah, another one. Well I'm sure you can make yourself useful. Here. Go kill a zombie or two.

Try not to die.
ITEM stone_sword

KILL zombie 5

ITEM cookie
Well at least you're not useless. Here's a bandaid. And since you've been such a good boy, a cookie as well.

===
Supplies
Eldaria
1600 AD

NPC alex
===

You'll probably want to get up to speed with everything.
I'm not the best one for that, so go meet the guy who runs the inn on the way to Miran Des. Just follow the road.

ITEM paper
While your at it, give him this supply sheet. We're low on supplies. When you've gotten them, hand them to me.

NPC innkeeper

GIVE paper

ITEM potion 1 8257
Ah. Welcome, welcome. Come sit down and rest up.

What is this place? Hmmm. *puff* Where to start?

This land used to be filled with dragons you know. It was their home before we came. We lived with them for a time, but things grew complicated as friendships always do. We drove them off. Well, killed em all really. That was years ago now.

The last ones fell just near here at the heart of Miran Des. You ought ta go check out them bones. Huuuuge. Each one was near a quarter of the Tower in height.

Well now. If you're off in that direction, ask Steve over there. He's a mage. He'll know more of the specifics on the dragons and the Tower.

ITEM apple 64
Oh and before you jaunt off to Miran Des with him. Take these supplies over to the guys back at the portal.

NPC alex

GIVE apple 64

Thanks for bringing the supplies foreigner. Now get on your way to Miran already.

Turns into this:

'Rift: New Players':
  texts:
    description: 'Rift: New Players'
    completion: 'Rift: New Players completed'
    acceptance: 'Rift: New Players started'
  repeats: 0
  objectives:
    '0':
      '0':
        type: talk
        npcdestination: 0
        message: The Rift is a seperate entity outside of time and space. Here generations before you have made it simple to go to any slot in time you wish. The portal behind me will take you to Eldaria in the year 1600 AD.
    '1':
      '0':
        type: talk
        npcdestination: 0
        message: To open a portal, throw the lever beside it, but be sure to quick and step through before the portal closes!
    '2':
      '0':
        type: talk
        npcdestination: 0
        message: Some portal can take you to multiple places, to chose one, click the panel beside the lever till the desired target is selected.
    '3':
      '0':
        type: talk
        npcdestination: 0
        message: Now step forth and try it. Then witness with your very eyes, the fall of Eldaria.
    '4':
      '0':
        type: talk
        npcdestination: 0
        message: '* The guardian hands you a book for you to pen your adventure. Then
          lightly shoves you towards the portal.'
        rewards:
          '0':
            type: item
            id: 340
            amount: 1
            data: 0
            take: false
'(1600 AD) Eldaria: Go Kill Zombie':
  texts:
    description: '(1600 AD) Eldaria: Go Kill Zombie'
    completion: '(1600 AD) Eldaria: Go Kill Zombie completed'
    acceptance: '(1600 AD) Eldaria: Go Kill Zombie started'
  repeats: 0
  requirements:
    '0':
      type: quest
      quest: 'Rift: New Players'
      take: false
  objectives:
    '0':
      '0':
        type: talk
        npcdestination: 5
        message: Ah, another one. Well I'm sure you can make yourself useful. Here. Go kill a zombie or two.
    '1':
      '0':
        type: talk
        npcdestination: 5
        message: Try not to die.
        rewards:
          '0':
            type: item
            id: 272
            amount: 1
            data: 0
            take: false
    '2':
      '0':
        type: hunt
        amount: 5
    '3':
      '0':
        type: talk
        npcdestination: 5
        message: Well at least you're not useless. Here's a bandaid. And since you've been such a good boy, a cookie as well.
      rewards:
        '0':
          type: item
          id: 357
          amount: 1
          data: 0
          take: false
'(1600 AD) Eldaria: Supplies':
  texts:
    description: '(1600 AD) Eldaria: Supplies'
    completion: '(1600 AD) Eldaria: Supplies completed'
    acceptance: '(1600 AD) Eldaria: Supplies started'
  repeats: 0
  requirements:
    '0':
      type: quest
      quest: '(1600 AD) Eldaria: Go Kill Zombie'
      take: false
  objectives:
    '0':
      '0':
        type: talk
        npcdestination: 5
        message: You'll probably want to get up to speed with everything.
      '1':
        type: talk
        npcdestination: 5
        message: I'm not the best one for that, so go meet the guy who runs the inn on the way to Miran Des. Just follow the road.
    '1':
      '0':
        type: talk
        npcdestination: 5
        message: While your at it, give him this supply sheet. We're low on supplies. When you've gotten them, hand them to me.
      rewards:
        '0':
          type: item
          id: 339
          amount: 1
          data: 0
          take: false
    '3':
      '0':
        type: delivery
        npcdestination: 6
        item:
          id: 339
          amount: 1
          data: 0
    '4':
      '0':
        type: talk
        npcdestination: 6
        message: Ah. Welcome, welcome. Come sit down and rest up.
      rewards:
        '0':
          type: item
          id: 373
          amount: 1
          data: 8257
          take: false
    '5':
      '0':
        type: talk
        npcdestination: 6
        message: What is this place? Hmmm. *puff* Where to start?
    '6':
      '0':
        type: talk
        npcdestination: 6
        message: This land used to be filled with dragons you know. It was their home before we came. We lived with them for a time, but things grew complicated as friendships always do. We drove them off. Well, killed em all really. That was years ago now.
    '7':
      '0':
        type: talk
        npcdestination: 6
        message: The last ones fell just near here at the heart of Miran Des. You ought ta go check out them bones. Huuuuge. Each one was near a quarter of the Tower in height.
    '8':
      '0':
        type: talk
        npcdestination: 6
        message: Well now. If you're off in that direction, ask Steve over there. He's a mage. He'll know more of the specifics on the dragons and the Tower.
    '9':
      '0':
        type: talk
        npcdestination: 6
        message: Oh and before you jaunt off to Miran Des with him. Take these supplies over to the guys back at the portal.
      rewards:
        '0':
          type: item
          id: 260
          amount: 64
          data: 0
          take: false
    '11':
      '0':
        type: delivery
        npcdestination: 5
        item:
          id: 260
          amount: 64
          data: 0
    '12':
      '0':
        type: talk
        npcdestination: 5
        message: Thanks for bringing the supplies foreigner. Now get on your way to Miran already.

As you can see, it’s still needs to be improved upon. Mainly the saving of objectives, and filtering default settings to keep filesize down. The schema of the scripts are built like so:

root
    header
        name
        world
        time
        npc
    body
        objective (new step)
        objective

        objective (new step)

        objective (new step)

        switch target npc for all following objectives (for diliveries and talking)

        objective (new step)
        objective

As you can see, it allows long conversations to be written very easily. The builder itself deals with all the counting.

To Do

  • Add the rest of the objective types (and rewards).
  • Add a config file to skin text messages with:
  • (Click to continue) as a suffix and greyed out.
  • Option for a prefix.
  • Prefixes include putting the targetted NPC’s name in front like so: Name: blah
  • Manage the npc-profiles. Making specified NPCs a quester.
  • Option for sidequests and non-linear plot. My thoughts are to keep the automatic linking to the last quest unless specified as a sidequest or a required quest has been mentioned.
  • Parametered titles in the config.
    • 1 param: %1$s
    • 2 param: %2$s: %1$s
    • 3 param: (%3$s) %2$s: %1$s
  • Allow quests.txt to be broken up into several files by moving it into a subfolder. The parser would then read files alphabetically.
    • 0-start.txt
    • 1-training.txt
    • 2-sword1.txt
    • 3-mage1.txt
    • sidequests.txt

 

Citizens Editor Update – Loading

I managed to easily get the design and mocked up elements done well within the time limit.   From there I jumped right into learning how to make the tables and lists actually load data from Citizens. This involved deciphering the loading process of the plugin. I soon found that I would be unable to use the default plugin and would need to rewrite a few parts. They mostly revolved around the relative folder the plugin was launched from. The things I did were:

  • I copied and refactored a few functions to remove all mention of Entity and Server.
  • I needed to create an abstracted implementation of World for Location.
  • Since the npc data isn’t stored in some list in the plugin (it was a list/map of HumanNPC which extended Entity), I need to manage it in the editor.

One of the easiest things to get was the NPC types, as the loading of them (.jars) was completely separate from everything else.

My current state is learning about JTable’s and Focus Listeners so that I can have the NPCDetailsPanel show the details of the NPC. I’ve managed to load the NPC data and populate the index table.

So far I’ve spent 6 hours (2 for planning) on this project. Exploring new areas such as tables and it’s listeners is really eating away at the time spent as I don’t believe I’m doing the standard approach.

 

 

New Project: Citizens Editor

Designing a quest based server makes dealing with Citizen’s configurations terribly annoying. So I decided to plan this project out first (crosses fingers and hopes it doesn’t turn out like my last planned project).

Since this will revolve around a technology I’ve not profected (GUIs), I’ll be needing to associate time to learn new skills and build familiarity with it. I will be speeding this process up by using the Netbeans IDE.

Time Limits

Instead of planning the whole project out, I’ll instead do it in parts. After each part, I will re-evaluate and plan the next time slots.

  • Design: 1 Hour
  • Build the GUI: 1 Hour

Wish me luck.

Gimp 2.7.4 Review

Gimp is an awesome open-source alternative to Photoshop. However, it’s rather lacking in a few places. This review is using the 2.7.4 development build for windows found here.

  • Floating point settings (eg: 0.00) increment by the hundredth (0.01) when using the arrow buttons. Same with hovering over and scrolling as well as click-draging left and right. For most use cases, this is fairly useless when your range of values can be from 0.01 to 1000.00 (in the case of brush size). That’s a lot of scrolling. The click drag usually also forces the user to delete numbers to round it manually, making the functionality useless when quick precision is desired.
    • Change incremental values to jump by integer. This is done with spacing (lower right in 2.7) which is a 0.0 floating point.
    • Possibly change incremental values to scale exponentially when scrolling. Then click-drag for more precision change linearly.
  • The Palette Editor is nice once you find it. Clicking tiny 10px squares is not fun though. Sure a palette can be hundreds of colours in size, but that doesn’t mean we need to make choosing colours intolerable. Especially with palettes with only 10 – 20 colours. The dialog box is full of whitespace. There are buttons to zoom and change the number of rows at the bottom, however the defaults are awful.
    • Increase default size of boxes.
    • Edit: I found the Colors toolbox, which has a much better viewer of the current selected palette. Makes sense when the other is called “Editor”. It fills whitespace very well when there are only a few colours. My only ilk about it is that it does it’s best to not use a scrollbar, causing huge palettes to have the boxes with a tiny side.
      • Add/Change the minimum size, and use a scrollbar once reached a certain limit.
  • Also, the palette editor could do with a tooltip that shows a larger box with the colour, along with it’s hex / rgb value to help with choosing colours in a gradient filled palette. The tooltip could be used for other purposes as well. Examples that come to mind are a larger preview of brushes and textures. A delayed tooltip (so as to not slow old computers) for fonts.
  • Modify default toolboxes. Channels (RGBA) is probably not used by the average joe. Colors would be useful as a default (redundant due to the color picker yes, but would make choosing colour faster).
  • Making palettes seems to be fairly textbox heavy. A solution would be to have a dynamic palette similarly to the one in the colour picker popup. This would be the default palette, and would reset on every startup. The list of colours in the palette colour picker would need to be more than 12 however. This way, a user could create palettes as they go. Since the Colors toolbox does not add to this dynamic palette automatically, a button beside the eyedrop would suffice.

New Project: Vault Promoter

This project was spurred by the fact that bPermissions’s promotion system limitations. While it focus’s on tracks, the actual permission node for each track uses one node per group. My desired setup was that normal users could promote Guests. Giving users the promote.User permission node would then allow users the ability to both promote to guests to User and to demote them from it. Not ideal. While I first debated forking and submitting a patch (which I half did), I also wanted the promotion commands to be more configurable. Currently they were /promote [trackname]. Which would force a mod use the command more than once to go all the way from Guest -> Mod.

VaultPromoter uses Vault as a backend so it should work with all permission plugin it can use. The commands are configurable, as well as the text sent to the players. The text also takes context into account. Commands are in the format:

/<command> target1 target2

To Do

  • I still need to make a settings file and it’s parser as all planned settings are all hardcoded in.
  • If I plan on putting this on Bukkit Dev, I’ll also need to make an installer that will create a default configuration file(s).
  • I will need to get my old color code filters and word wrapping put into this plugin.

StumbleUpon Share Bookmarklet

One of the most annoying things about using Chrome is the StumbleUpon extension. It’s a terrible port for those used to the responsiveness of Firefox’s addons UI. Clicking on the Icon will inject an iframe, which takes a bit to load. That same iframe is injected for every page thereafter until you click the SU icon again. The annoying part is that it’s slow. It needs to load a bunch of javascript when you want it, and when you don’t want it. The latter being when it’s loading on every next page till you turn it off.

So what can be done about it?

If I were to write a full extension, I’d scrap the whole ‘toolbar’ idea. Chrome supports very minimal UI options, but it does have some! First off, it has the notification buttons. If Chrome doesn’t limit you to only 1 button per extension, why not make the major stumble button and a separate button to have a menu for Share, Account, etc.

Since it looks like you can only have one browser_action (button) per extension, then try moving the “stumble” browser_action into the top of the stumble menu browser_action. Then launch a stumble button extension for power users that don’t like having to click+wait+click for random stumbling.

Unfortunately, I’m still rather hackish in javascript. I know my way round the syntax, but writing an extire Chrome extension is beyond me for now. So instead, I focused on what I actually use the toolbar for.

I only use the toolbar for the share button and drop down. I get email alerts whenever a friend shares with me, which combined with a GMail Notifier gives me a live view of my friends shares. I rarely (/never) use the Stumble button anymore since I’ve started browsing Reddit.

The StumbleUpon Share Bookmarklet

So ultimately, I wrote a bookmarklet to inject just the share box.

Source:

javascript:
(function(global){

global.SUT = {
    sharePanelUrl: function(url) {
        return 'http://www.stumbleupon.com/share/?url='+url+'&src=website&mode=toStumbler';
    },
    closeSharePanel: function() {
        SUT.deleteNode(document.getElementById('SUshareWrapper'));
    },
    deleteNode: function(n) {
        n.parentNode.removeChild(n);
    }
};

var d = document,
    b = d.getElementsByTagName('body')[0],
    w = d.createElement('div'), // Wrapper
    wS = w.style; // Wrapper.style

wS.top = '0';
wS.left = '0';
wS.width = '100%';
wS.zIndex = '999';
wS.position = 'fixed';
wS.backgroundColor = '#fff';
wS.borderBottom = '1px solid black';
wS.textAlign = 'center';
w.id = 'SUshareWrapper';
w.innerHTML = '<iframe src="'+encodeURI(SUT.sharePanelUrl(d.URL.split("#")[0]))+'" style="width: 100%; height: 300px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; overflow-x: hidden; overflow-y: hidden; "></iframe><input type="button" width="100%" height="15px" onclick="javascript:SUT.closeSharePanel()" value="Close"></input>';
b.appendChild(w);

})(typeof exports != 'undefined' ? exports : this);

Creating the Bookmarklet

Creating the bookmarklet was fun. It is by all means not perfect probably, as I didn’t sweep through it for minimalism. Nor is setting a global object the best approach. I also found out that browsers (or just Chrome?) don’t let you get objects created in a top frame from an iframe unless the protocol and domain match. Thus I wasn’t able to hook the closing call after a successful share.

I also found out that dynamically created fixed objects will have it’s x coordinate relative to the #anchor tag if found. I relearned to always encode my URLs before submitting them as parameters.

The best tool for bookmarklets however, is a javascript compressor. This let’s you write in a decent working environment (readable variable names), before ‘compiling’ it for the bookmarklet. Last but not least, always use ‘ and \’ when dealing with bookmarklets, at least if you’re planing to use the bookmarklet as a URL on a webpage.

Fruits of Todays Labours – jsPaint

I love DeviantArt’s Muro sketchpad. It’s freaking amazing. I just don’t want every doodle to end up in my DA gallery. So, I needed a different image host. Just so happens Imgur has an API, with examples (well rough ones). I also just so happen to be wanting a project to learn JQuery. Thus, this new project was born.

Right now, it has the ability to anonymously upload the canvas to Imgur. This took a fair bit of tinkering as there’s no set standard yet for sending canvases as FormData. I ended up combining a few scripts together to get a getBlob() function working (blob has got to be the most ambiguous name ever for this functionality).

I read a few tutorials on creating a basic painting app so that I could test out a simple creation. I found this article to be fairly good to draw actual lines. I’ll be looking into a better method later, as right now this code is running on only two classes which are barely used.

I added a nice brush size cursor overlay, and let the mousewheel control the brush size like in Photoshop with the appropriate JQuery plugin.

My next goal is getting the drawing part to have layers, and an undo function. Both require a well thought out bunch of classes, which is why I haven’t bothered tackling them yet. From there I can make keyboard shortcuts.

You can try the latest demo at: http://xshade.ca/draw/index.html or check out the code on GitHub.

Day 1

Spent more than 8 hours. Oh well. You tend to have major code rushes at the start of a new project.

  1. Planning
  2. Tiles
  3. Blarg PyGame. Blarg Pngs. Blarg transparency.
  4. Not pixel perfect.
  5. Reusing old code for the engine.
  6. Render order.
  7. Nicer looking tiles. Pause screen.
  8. Major Rewrite of grid layering. Instead of a different surface for each tile/layer, blit each cell to a single surface.
  9. Player Spritesheet and render player.
  10. Player can move with keyboard input. Fancy selection hover effect.
  11. Simple pathfinding that incoperates height.
  12. Fixing up movement from pathfinding. Move the camera as player moves.
  13. Working on teleporting