Showing posts with label Code. Show all posts
Showing posts with label Code. Show all posts

Saturday, 28 August 2010

0.05c source archive now available

As promised, a source-only distribution for v0.05c is now available here (also linked from the menu on the right)

Tuesday, 4 May 2010

C# Cartesian Point class

I've developed a class for using Points in C# (unlike Delphi, there's no inbuilt type). You can grab the source code and a sample console app here or here. All code is public domain, knock yourself out, etc, etc, etc.

Saturday, 17 April 2010

First batch of changes for v0.05c uploaded to the repository

I've uploaded the first batch of changes to the code for the next version to the online source-code repository. Fixes & Updates completed in the code so far are:
  • Some monsters now follow characters up and down stairs.
  • Classes now have different titles, dependent upon current character level.
  • Only the just finished game will be now highlighted correctly in the hiscore list after character death.
  • Spurious double quotes (") will no longer appear in automatically generated character names.
  • When resting, there is chance of a monster appearing randomly near the character.
  • Eating now restores all lost health points.
  • When starting a 2nd game in the same session, the Character Background will be reset properly.
  • On Character death, the Main Window Title will be reset properly.
  • Elemental Intrusion Creatures no longer have as many hitpoints.
  • Unidentified Scrolls are now identified properly on Character Death.
I'll not produce an executable release for these, but I'll wait until the other changes (including potions!) are finished before releasing the next version (some of them are incomplete in the code but don't affect compilation).

You are of course welcome to download and compile the latest version if you are in a position to do so.

Tuesday, 13 October 2009

Configuring and compiling Kharne - a brief guide

(this is a copy of CODING.TXT which is found in the source code distribution. I will also add a permalink to this post for reference purposes)

Contents:
  1. Introduction
  2. Required 3rd Party Components
  3. Licensing Notes
  4. Other Notes
  5. Contact Details
1. Introduction

Welcome to Kharne. Kharne is a standard Delphi Windows application that uses a certain number of third-party controls and libraries for additional functionality above and beyond that provided in Delphi.

I have developed Kharne using Delphi 7, but provided the external controls can be installed, it should be compilable in any version of Delphi newer than 5.

2. Required 3rd Party Components

Due to licensing terms, I can't provide these components or distribute their source with my own distribution.

You will need to download and install the following before you open the source in Delphi for the first time:

a. TGradLabel
http://www.delphi32.com/vcl/929/#

It is my intention to phase the use of this component out entirely.

b. TAStarPathPlanneer
http://www.riversoftavg.com/tastarpathplanner.htm

c. TQProgressBat
http://mapage.noos.fr/qnno/pages/delphi_en.htm#TQProgressBar

d. TSQLLite
http://www.itwriting.com/blog/a-simple-delphi-wrapper-for-sqlite-3

You may need to add the path of this component to the Project Search Paths.

e. THotLog
http://mapage.noos.fr/qnno/pages/delphi_en.htm#hotLog

This isn't a component as such, simply copy hotlog.pas into the source directoy and make sure it is added to the project.

f. TKeyboardHandler

As this is no longer available *anywhere* on the web, I've included the source in the components subdirectory. Longer term I want to phase use of this component out and duplicate its functionality,

g. sqlite3.dll

This is the SQLLite interface library, is public domain and thus is included with this source distribution.

If any of these components become unavailable, contact me (starbog@gmail.com) and I will send them to you direct (I will only do this under these circumstances). I will then try and remove any dependency upon them from the next version.


3. Licensing Notes

I have released Kharne under the MPL as opposed to the GPL because I'm not convinced that the latter allows a Delphi program to link with components that are not GPL themselves.

I've had a reply direct from the FSF telling me that it does provided I add an additional disclaimer to the GPL License that gives explicit permission. However, as I'm not convinced about this (the GPL itself is quite fuzzy in this regard), I'm releasing Kharne under the MPL to avoid any doubt.

However, just to clear things up, I'm am granting an irrevocable right to link my code released under the MPL to any other custom component, library or API no matter what the license.

The source code file UnitOtherFuncs uses a few small routines freely available on the web - I have indicated carefully what these are in the source and their origins, and this file is obviously not released under the MPL.

The distribution also includes a copy of the Bitstream Vera Sans Mono Font (veramono.ttf) which can be freely distributed and is in the public domain. If you are doing development, please copy this and install it in the usual way before opening the source code.

4. Other Notes

I have no idea if Kharne will compile with Lazarus, I suspect the custom components may prove to be an unsurmountable obstacle, but anyone is welcome to try porting if they wish. I'd like Kharne to run multiplatform without using WINE, but that may have to wait until cross-compiling for Delphi becomes a reality (it has been promised for the version due out in 2010.)


5. Contact Details

I can be emailed direct at starbog@gmail.com or reached via the blog at kharne-rl.blogspot.com. Or you can reach me on #rgrd regularily where I am known as "starbog".

Sunday, 11 October 2009

Automatic notifications of commits

Does anyone know of a way to automatically post a message to a blog with summary details of a commit that's been made to a Googlecode SVN? (but not the email that's generated with all the changes)

Sunday, 4 October 2009

Saturday, 3 October 2009

Source Code Issues #1

dunkel^ on #rgrd has discovered a couple of gotchas with the current source code distribution that prevent compilation.

In the uses clause in the interface section of UnitDisplay.pas (line #33) I left an errant reference to a component I no longer use. If you remove BtChkBox from this clause, it solves this problem.

The new uses clause should look like this:

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, KeyboardHandler, DateUtils, jpeg, ImgList, Menus, ComCtrls, ToolWin, Gradlabl, PathPlanner, QProgBar, AppEvnts, hotlog, UnitDungeon, UnitDefines, UnitConst, UnitVars, UnitFunctions, UnitItem, UnitCreature, UnitMonster, UnitInit, UnitGame;

Also, the logging component, THotLog seems to be unreliable and AVs a lot. To disable it for now, just comment out the hLog.StartLogging call in the TFormSplash.FormCreate method in UnitSplash.pas (line #66):

{ Form Create }
procedure TFormSplash.FormCreate(Sender: TObject);
begin
{ Set up Logging }
hLog.hlWriter.hlFileDef.append := False;

{ Start Logging }
//hLog.StartLogging;

{ log System Information}
hLog.add('{OSVI}');
hLog.add('{CPUI}');
hLog.add('{mem}');

With these changes, Kharne was able to be compiled and ran successfully.

Thursday, 1 October 2009

Kharne 0.05 and source code released!

Kharne Alpha v0.05 is now available, and has been released as open source under the MPL v1.1

This version is functionally identical to v0.04a.

The source code is available here or via the downloads menu.

Please read CODING.TXT in the docs subdirectory before attempting to load the Kharne project into Delphi.

If you have any questions, or difficulty getting the source to compile, feel free to leave a comment here or email me on starbog@gmail.com.

Thursday, 6 August 2009

Implementing Transient Events: The TGameTimer class

One of the most difficult tasks in programming a roguelike is to handle transient events, such as poison, strength buffs and so on. As well as the effects (lose a HP! gain strength!), you've got to keep track of the duration, and deal with cancelling the events. One (obviously unsatiisfactory) way of implementing this is to hard code it The other, is to use a class to handle such events.

Hence the TGameTimer class.

I've made the full source code available here and here, and also listed it below (you may need to copy and past to get around wordwrapping issues). Although written in Delphi, it should compile in FreePascal without too many changes (if any). I'm releasing it as public domain, so feel free to use and abuse it as you see fit.

Basically, the class uses good ole' Procedure Pointers to allow (optional) event hooks to occur in three scenarios:

  • Upon Event Creation
  • Upon an Event Tick
  • Upon Event Expiry

The constructor of the object takes an event type and an event duration in turns. as well as the event hooks themselves.

If anyone wants a demo app showing the class in action, let me know and I'll post one. Otherwise, you'll have to wait until the next major release of Kharne, when I intend to use TGameTimer to implement potion functionaility (finally!).

I'll do a followup post over the weekend with some additional comments, and thoughts on how it can be improved. In the meantime, comments are most welcome.


{ Timer Handling

A TGameTimer represents a transient event that has a duration.

An example would be the side-effects of drinking a Potion of Might - it increases
strength for a limited number of turns. We optionally define a number of procedure
pointers to point to events that occur at the beginning and end of the duration,
and also on every turn.

For example, upon drinking a Potion of Might, the event might display a message
stating you feel mighty (as well as increasing your strength). As the duration
of the effects decrease, further messages will be displayed stating that the
effects of the potion are wearing off, and then when the duration has expired,
your strength reverts back to normal

To implement this, use the follwing steps as a guide:

1. Set up a variable:

DrinkMightPotionEvent: TGameTimer;

2. Define three events as follows:

procedure MightPotionDrink(const Turns: Integer = 0);
procedure MightPotionTick(const Turns: Integer = 0);
procedure MightPotionEnd(const Turns: Integer = 0);

procedure MightPotionDrink(const Turns: Integer);
begin
DisplayMessage('You feel mighty!');
Player.Strength := Player.Strength + 10;
end;

procedure MightPotionTick(const Turns: Integer);
begin
if (DrinkMightPotionEvent.Progress = 50) then
DisplayMessage('The effects are wearing off!');
Player.Strength := Player.Strength - 5;
end;

procedure MightPotionEnd(const Turns: Integer);
begin
DisplayMessage('You no longer feel so mighty!');
Player.Strength := Player.Strength - 5;
end;

3. Instantiate the event:

DrinkMightPotionEvent := TGameTimer.Create(timMight,
DURATION_MIGHT_POTION,
MightPotionTick,
MightPotionDrink,
MightPotionEnd);

4. Then, on every turn that passes, simply call

if (Assigned(DrinkMightPotionEvent)) then DrinkMightPotionEvent.Tick;

}

{ Define the types of timers as an enum for simplicity }
type TGameTimerType = (timSpeed,
timConfusion,
timBlindness,
timSeeInvisible,
timParalysis,
timFreeAction,
timCombatMastery,
timReflexes,
timMight);

{ Procedure Pointer for Event Hook }
type TGameTimerEvent = procedure(const Turns: Integer = 0);

{ Class Definition - it inherits the ICommonObject interface to gain access
to the StringValue method to allow easy persistance }
type TGameTimer = class(ICommonObject)
private
FTimerType: TGameTimerType; // Timer Type, from the enum previously defined
FTimerDuration: Integer; // Starting Duration, in turns
FTimerDurationLeft: Integer; // Duration Left, in turns
FTimerTickEvent: TGameTimerEvent; // Optional Event to call on each decrement
FTimerStartEvent: TGameTimerEvent; // Optional Event to call on starting the timer
FTimerEndEvent: TGameTimerEvent; // Optional Event to call on ending the timer (i.e. turns left = 0)

{ Private functions to support class properties defined below }
function GetStatus: Boolean;
function GetProgress: Integer;

public
{ Standard Constructor }
constructor Create(TimerType: TGameTimerType;
TimerDuration: Integer;
TimerTickEvent: TGameTimerEvent = nil;
TimerStartEvent: TGameTimerEvent = nil;
TimerEndEvent: TGameTimerEvent = nil);

{ Decrement the Timer by one turn. Will return true if the timer has not expired }
function Tick: Boolean;

{ Interface Method for Persistance }
function GetStringValue: String;

{ Properties }
property TimerType: TGameTimerType read FTimerType; // Return the enum
property TimerDuration: Integer read FTimerDurationLeft; // Number of Turns left
property TimerProgress: Integer read GetProgress; // Number of Turns left as a percantage (0-100) of the original duration
property Active: Boolean read GetStatus; // True if Number of Turns left is > 0
end;


implementation

{ Standard Constructor - this is deliberately the only way to set up the duration etc }
constructor TGameTimer.Create(TimerType: TGameTimerType;
TimerDuration: Integer;
TimerTickEvent: TGameTimerEvent;
TimerStartEvent: TGameTimerEvent;
TimerEndEvent: TGameTimerEvent);
begin
{ Load the private member data }
FTimerType := TimerType;
FTimerDuration := TimerDuration;
FTimerDurationLeft := TimerDuration;
FTimerTickEvent := TimerTickEvent;
FTimerStartEvent := TimerStartEvent;
FTimerEndEvent := TimerEndEvent;

{ If we have a start event defined then execute it now }
if (Assigned(FTimerStartEvent)) then
FTimerStartEvent(FTimerDurationLeft);
end;

{ Return true if the timer hasn't expired }
function TGameTimer.GetStatus: Boolean;
begin
Result := FTimerDurationLeft > 0;
end;

{ Decrease the duration of the timer by a turn }
function TGameTimer.Tick: Boolean;
begin
Dec(FTimerDurationLeft);

{ Trigger events if they are defined }
if (FTimerDurationLeft > 0) then
begin
{ Interval Event }
if (Assigned(FTimerTickEvent)) then
FTimerTickEvent(FTimerDurationLeft);
end
else if (FTimerDurationLeft = 0) then
begin
{ End Event }
if (Assigned(FTimerEndEvent)) then
FTimerEndEvent(FTimerDurationLeft);
end;

{ Return true if the Timer is still active }
Result := GetStatus;
end;

{ Returns the number of Turns left as a percantage (0-100) of the original duration }
function TGameTimer.GetProgress: Integer;
var
Percentage: Double;
begin
Percentage := FTimerDurationLeft / FTimerDuration;
Result := Trunc(Percentage * 100);
end;

{ Get the Timer as a String }
function TGameTimer.GetStringValue: String;
begin
{ TODO: We will need to extend this to allow hashing of the attached procedures }
Result := Format('%d%d', [Ord(FTimerType), FTimerDuration]);
end;

Thursday, 26 March 2009

Some thoughts on Open Source

With the release of the first non-Alpha version of Kharne (0.1), Kharne will officially go open-source (with code probably available on GoogleCode).

But not under the GPL.

This is because I use some custom Delphi components that themselves aren't open-source, and this is incompatible with the viral nature of the GPL.

Instead I will be releasing Kharne under the Mozilla Public License (MPL):

"The MPL treats the source code file as the boundary between MPL code and proprietary parts, meaning that a certain source file (e.g., C++, JavaScript or XUL file) is either fully MPL or fully proprietary. The GPL, in contrast, uses the process boundary of the executable as the license boundary..."

In other words, under the MPL, which is a weak copyleft license, code that I write is considered open source - but the code of third party components is not:

"[The MPL] allows for the combination of MPL code with other code in a larger work without requiring that all code in the entire work be distributed under the same license..."

I have contacted the authors of those third-party components concerned and received explicit permission for use of their components in the compiled binaries of an open source project, and linking to them in my open-sourced code.

Obviously, I cannot and will not distribute their source code.

Rather, I will, per their own license terms and that of the MPL, include instructions in the source distribution on how to obtain and install their components independently.

And that is a win all round.