Monday 26 March 2012

Been a while

It's been a while since I last made an update. This isn't because I've been slacking though; I've just been working on technical things like loading files, detecting when windows are opened and closed, etc. Nothing really cool that I can show you. However, I did create this Python script for generating an ITEM file (.item). The game itself has a C++ version, but since I haven't gotten around to getting a Windows compile together yet no one can really use it.

 ## Python ITEM writer script for Tyran  
 ## Version: 1.0  
 ## 19/3/2012  
 ## ITEMcreator.py  
 ################################  
 # This script is a little sloppy. It gets the job done though.  
 #  
 # Copyright (c) 2012 Joshua Woods  
 #  
 # This software is provided 'as-is', without any express or implied warranty.  
 # In no event will the authors be held liable for any damages arising from  
 # the use of this software.  
 #  
 # Permission is granted to anyone to use this software for any purpose,  
 # including commercial applications, and to alter it and redistribute it freely,  
 # subject to the following restrictions:  
 #  
 # 1. The origin of this software must not be misrepresented; you must not  
 # claim that you wrote the original software. If you use this software in a  
 # product, an acknowledgment in the product documentation would be  
 # appreciated but is not required.  
 #  
 # 2. Altered source versions must be plainly marked as such, and must not  
 # be misrepresented as being the original software.  
 #  
 # 3. This notice may not be removed or altered from any source distribution.  
 ################################  
 ## Updated: 24/3/2012  
 ################################  
   
 itemVersion = 0x0002 # please do not change  
 magic = 'ITEM\0' # please do not change  
   
 ################################  
 ## These classes are currently not used. But may be used in the future.  
 ################################  
 class itemType:  
      NONE, WEAPON, ARMOUR, CONSUMABLE, INGREDIENT, MATERIAL = range(6)  
   
 class itemQuality:  
      NONE, CRUDE, PETTY, COMMON, SUPRERIOR = range(5)  
   
 class itemEffect:  
      NONE, HEALTHHEAL, HEALTHHARM, MANAHEAL, MANAHARM, FATIGUEHEAL, FATIGUEHARM, HUNGERHEAL, HUNGERHARM, SLOW, HASTE,FORTSTR,FORTAGI,FORTPER,FORTINT,FORTCON,FORTWIS,FORTSPD,WEAKSTR,WEAKAGI,WEAKPER,WEAKINT,WEAKCON,WEAKWIS,WEAKSPD,RESISTPOISON, VULNURPOISON,RESISTDISEASE,VULNURDISEASE,RESISTMAGIC,VULNURMAGIC,RESISTPARALYSIS,VULNURPARALYSIS,CUREPOISON, CUREDISEASE,INVISIBILITY,DIZZY,INSANITY,FEAR,KILL = range(40)  
        
   
 ################################  
 ## Default values  
 ##  
 ## Don't alter these without knowing exactly what  
 ## you're doing. Some values like -666 are important  
 ## to the way Tyran determines ITEM versions.  
 ################################  
   
 fileName = 'newitem.item'  
 fileNameSub = fileName.split('.')  
 weight = 0  
 type = 0  
  # f 0, it is indestructible  
 durability = 0  
 #maximum durability  
 maxdur = 0  
 # higher the quality, the less chance of durability being decreased. 1 is to lose 1 durability per use.  
 quality = 0  
 equipable = 0  
 placeable = 0  
 description = 'item description (max 256 chars)\0'  
 name = 'item name (max 64 chars)\0'  
 # type of effect if consumable (eg. Healing) and the magnitude of the effect(eg. 20 would heal 20 points)  
 effect1 = 0  
 effect2 = 0  
 effect3 = 0  
 magnitude1 = 0  
 magnitude2 = 0  
 magnitude3 = 0  
   
 meshpath = "Models/Plane.obj\0"  
 texturepath = "Textures/texture_basecube.bmp\0"  
   
 armour = -666  
   
 ################################  
 welcomeMessage = '\nWelcome :) Change the values below and when you\'re done hit the Export button. Things to be aware of:\n\nDurability, maxdur, weight and armour only take integers.\nItem description takes a maximum of 256 characters\nItem name, mesh path and texture path take a maximum of 64 characters.\n\nIf you don\'t follow these rules, Tyran will crash when it tries to load the ITEM file.\n\nITEM versions supported: %d, %d' % (0x0001, itemVersion)  
 ################################  
   
 import os.path, tkMessageBox, sys, struct  
 import Tkinter as tk  
 from Tkinter import *  
 from string import rstrip, split  
   
 ################################  
 ## Check fileName already exists as a file. If it does, rename  
 ## fileName.  
 ################################  
 def ifFileExistsRenameIt():  
      global fileName  
      global fileNameSub  
      if os.path.isfile(fileName):  
           # Check if file is already there  
           if os.path.isfile(fileName):  
                # File does exist, rename our new file  
                temp = fileName.split('.')  
                print temp  
                i = 0  
                print temp[0] + repr(i)  
                while i != 100: # you can't possibly have more than 100 unnamed ITEM files, can you?  
                     while 1:  
                          if temp[0] == fileName + repr(i):  
                               i += 1  
                            
                          final = fileNameSub[0] + repr(i) + '.' + fileNameSub[1]  
                            
                          print 'Final: %s' % final  
                          fileName = final  
                          if os.path.isfile(fileName) != True:  
                               break  
                          i += 1  
                                 
                     break  
   
 ################################  
   
 ################################  
   
 def settings():  
      tkMessageBox.showinfo('Sorry','This feature isn\'t available yet.')  
   
 def quit():  
      sys.exit(0)  
   
 def about():  
      abo.deiconify()  
      abo.mainloop()  
   
 def hideabout():  
      abo.withdraw()  
   
 class About:  
      def __init__(self,master):  
           frame = Frame(master)  
           frame.pack()  
           # Label  
           lbl = Label(master, text='ITEM Creator v1.0\n\n19/3/2012\nJoshua Woods\n\ntyrangame.blogspot.com.au')  
           lbl.config(font=("arial", 12, 'bold'), justify=LEFT, fg='royalblue',bg='black')  
           lbl.pack()  
   
 class Help:  
      def __init__(self, master):  
           frame = Frame(master)  
           frame.pack()  
             
           lbl = Label(master, text='contact me for help on this format.')  
           lbl.config(font=("arial", 12, 'bold'), justify=LEFT, fg='royalblue',bg='black')  
           lbl.pack()  
   
 class Program:  
      def __init__(self, master):  
           frame = Frame(master)  
           frame.pack()  
             
           scrollbar = Scrollbar(master)  
           scrollbar.pack(side=RIGHT, fill=Y)  
             
           #self.canvas = tk.Canvas(frame, bg='black', bd=3, relief='sunken')  
             
           self.cmbDataItemType = StringVar(master)  
           self.cmbDataItemType.set("Item type: None") # default value  
   
           self.w = OptionMenu(master, self.cmbDataItemType, "Item type: None", 'weapon', 'armour', 'consumable', 'ingredient', 'material')  
             
           self.cmbDataItemQual = StringVar(master)  
           self.cmbDataItemQual.set("Item quality: None") # default value  
             
           self.w2 = OptionMenu(master, self.cmbDataItemQual, "Item quality: None", 'crude', 'petty', 'common', 'superior')  
             
           self.cmbDataPlaceable = StringVar(master)  
           self.cmbDataPlaceable.set("Placeable: False") # default value  
             
           self.w3 = OptionMenu(master, self.cmbDataPlaceable, "true")  
             
           self.cmbDataEquipable = StringVar(master)  
           self.cmbDataEquipable.set("Equipable: False") # default value  
             
           self.w4 = OptionMenu(master, self.cmbDataEquipable, "true")  
             
           self.txtIntro = Text(master, yscrollcommand=scrollbar.set,font=('arial', 13, 'normal'),fg='yellow',bg='black',width=40, height=6,insertbackground='yellow',wrap=WORD,borderwidth=4)  
             
             
             
           self.txtfilename = Text(master,font=('arial', 13, 'normal'),fg='royalblue',bg='black',width=40, height=1,insertbackground='royalblue',wrap=WORD,borderwidth=4)  
           self.txtitemname = Text(master,font=('arial', 13, 'normal'),fg='royalblue',bg='black',width=40, height=1,insertbackground='royalblue',wrap=WORD,borderwidth=4)  
           self.txtitemdesc = Text(master,font=('arial', 13, 'normal'),fg='royalblue',bg='black',width=40, height=4,insertbackground='royalblue',wrap=WORD,borderwidth=4)  
           self.txtmeshpath = Text(master,font=('arial', 13, 'normal'),fg='royalblue',bg='black',width=40, height=1,insertbackground='royalblue',wrap=WORD,borderwidth=4)  
           self.txttexturepath = Text(master,font=('arial', 13, 'normal'),fg='royalblue',bg='black',width=40, height=1,insertbackground='royalblue',wrap=WORD,borderwidth=4)  
           self.txtdurability = Text(master,font=('arial', 13, 'normal'),fg='royalblue',bg='black',width=40, height=1,insertbackground='royalblue',wrap=WORD,borderwidth=4)  
           self.txtmaxdurability = Text(master,font=('arial', 13, 'normal'),fg='royalblue',bg='black',width=40, height=1,insertbackground='royalblue',wrap=WORD,borderwidth=4)  
           self.txtweight = Text(master,font=('arial', 13, 'normal'),fg='royalblue',bg='black',width=40, height=1,insertbackground='royalblue',wrap=WORD,borderwidth=4)  
           self.txtarmour = Text(master,font=('arial', 13, 'normal'),fg='royalblue',bg='black',width=40, height=1,insertbackground='royalblue',wrap=WORD,borderwidth=4)  
           self.btnexport = Button(master, text='Export', fg='royalblue', bg='black', command=self.btnexportcallback,font=('arial',13,'bold'))  
           # Packing:  
           self.txtIntro.pack(side=TOP, fill=BOTH)  
           scrollbar.config(command=self.txtIntro.yview)  
           self.btnexport.pack(side=TOP)  
           self.txtfilename.pack(side=TOP)  
           self.txtitemname.pack(side=TOP)  
           self.txtitemdesc.pack(side=TOP)  
           self.txtmeshpath.pack(side=TOP)  
           self.txttexturepath.pack(side=TOP)  
           self.txtdurability.pack(side=TOP)  
           self.txtmaxdurability.pack(side=TOP)  
           self.txtweight.pack(side=TOP)  
           self.txtarmour.pack(side=TOP)  
             
           #self.canvas.pack(side=RIGHT)  
           self.w.pack(side=LEFT)  
           self.w2.pack(side=LEFT)  
           self.w3.pack(side=LEFT)  
           self.w4.pack(side=LEFT)  
             
           #self.w.pack(side= RIGHT)  
           # Inject some data into new fields  
           self.txtIntro.insert(END, welcomeMessage)  
           self.txtfilename.insert(END, fileName)  
           self.txtitemname.insert(END,name)  
           self.txtitemdesc.insert(END,description)  
           self.txtmeshpath.insert(END, meshpath)  
           self.txttexturepath.insert(END, texturepath)  
           self.txtdurability.insert(END, "durability")  
           self.txtmaxdurability.insert(END, "maximum durability")  
           self.txtweight.insert(END, "weight")  
           self.txtarmour.insert(END, "armour")  
             
           #print drawWireframe(self.canvas, (200,200), meshpath)  
        
      def printValues(self):  
           #self.txtIntro.delete  
           self.txtIntro.insert(1.0, ("%s" % self.txtfilename.get(1.0, END)))  
           self.txtIntro.insert(1.0, ("%s" % self.txtitemname.get(1.0, END)))  
           self.txtIntro.insert(1.0, ("%s" % self.txtitemdesc.get(1.0, END)))  
           self.txtIntro.insert(1.0, ("%s" % self.txtmeshpath.get(1.0, END)))  
           self.txtIntro.insert(1.0, ("%s" % self.txttexturepath.get(1.0, END)))  
           self.txtIntro.insert(1.0, ("%s" % self.txtdurability.get(1.0, END)))  
           self.txtIntro.insert(1.0, ("%s" % self.txtmaxdurability.get(1.0, END)))  
           self.txtIntro.insert(1.0, ("%s" % self.txtweight.get(1.0, END)))  
           self.txtIntro.insert(1.0, ("\n%s" % self.txtarmour.get(1.0, END)))  
             
           self.txtIntro.insert(1.0, ("\n%s" % self.cmbDataItemType.get()))  
           self.txtIntro.insert(1.0, ("\n%s" % self.cmbDataItemQual.get()))  
           self.txtIntro.insert(1.0, ("\n%s" % self.cmbDataPlaceable.get()))  
           self.txtIntro.insert(1.0, ("\n%s" % self.cmbDataEquipable.get()))  
   
      def btnexportcallback(self):  
             
           # extract data from fields  
           fileName = (self.txtfilename.get(1.0, END)).strip()  
             
           weight = (self.txtweight.get(1.0, END)).strip()# + '\0'  
           if weight == 'weight':  
                weight = 0  
           else:  
                weight = int(weight)  
             
           durability = (self.txtdurability.get(1.0, END)).strip()# + '\0'  
           if durability == 'durability':  
                durability = 0  
           else:  
                durability = int(durability)  
             
           maxdur = (self.txtmaxdurability.get(1.0, END)).strip() #+ '\0'  
           if maxdur == 'maximum durability':  
                maxdur = 0  
           else:  
                maxdur = int(maxdur)  
             
           type = self.cmbDataItemType.get()  
           if type == "Item type: None":  
                type = 0  
           elif type == 'weapon':  
                type = 1  
           elif type == 'armour':  
                type = 2  
           elif type == 'consumable':  
                type = 3  
           elif type == 'ingredient':  
                type = 4  
           elif type == 'material':  
                type = 5  
             
           print type  
             
           quality = self.cmbDataItemQual.get()  
           if quality == "Item quality: None":  
                quality = 0  
           elif quality == 'crude':  
                quality = 1  
           elif quality == 'petty':  
                quality = 2  
           elif quality == 'common':  
                quality = 3  
           elif quality == 'superior':  
                quality = 4  
             
             
           equipable = self.cmbDataEquipable.get()  
           if equipable == "Equipable: False":  
                equipable = 0  
           else:  
                equipable = 1  
             
           placeable = self.cmbDataPlaceable.get()  
           if placeable == "Placeable: False":  
                placeable = 0  
           else:  
                placeable = 1  
             
           description = (self.txtitemdesc.get(1.0, END)).strip() + '\0'  
           name = (self.txtitemname.get(1.0, END)).strip() + '\0'  
             
           effect1 = 0  
           effect2 = 0  
           effect3 = 0  
           magnitude1 = 0  
           magnitude2 = 0  
           magnitude3 = 0  
   
           meshpath = (self.txtmeshpath.get(1.0, END)).strip() + '\0'  
           texturepath = (self.txttexturepath.get(1.0, END)).strip() + '\0'  
   
           armour = (self.txtarmour.get(1.0, END)).strip()# + '\0'  
           if armour != 'armour':  
                armour = int(armour)  
           else:  
                itemVersion = 0x0001  
             
           print weight  
           print equipable  
             
             
           ###############################  
           ifFileExistsRenameIt()  
           print 'Creating %s' % fileName  
           file = open(fileName, 'wb')  
           print 'Writing to file ...'  
           file.write(magic)  
             
           format = "h" # write short  
           data = struct.pack(format, itemVersion)  
           print '[' + repr(itemVersion) + ']'  
           file.write(data)  
           format = 'i' # write integers  
           data = struct.pack(format, weight)  
           print '[' + repr(weight) + ']'  
           file.write(data)  
           data = struct.pack(format, type)  
           print '[' +repr( type) + ']'  
           file.write(data)  
           data = struct.pack(format, durability)  
           print '[' + repr(durability) + ']'  
           file.write(data)  
           data = struct.pack(format, maxdur)  
           print '[' + repr(maxdur) + ']'  
           file.write(data)  
           data = struct.pack(format, quality)  
           print '[' + repr(quality) + ']'  
           file.write(data)  
           data = struct.pack(format, equipable)  
           print '[' + repr(equipable) + ']'  
           file.write(data)  
           data = struct.pack(format, placeable)  
           print '[' + repr(placeable) + ']'  
           file.write(data)  
           # effects and magnitude ignored for now  
           data = struct.pack(format, 0)  
           print '[' + repr(data) + ']'  
           file.write(data)  
           print '[' + repr(data) + ']'  
           file.write(data)  
           print '[' + repr(data) + ']'  
           file.write(data)  
           print '[' + repr(data) + ']'  
           file.write(data)  
           print '[' + repr(data) + ']'  
           file.write(data)  
           print '[' + repr(data) + ']'  
           file.write(data)  
             
           print '[' + name + ']'  
           file.write(name)  
           print '[' + description + ']'  
           file.write(description)  
           print '[' + meshpath + ']'  
           file.write(meshpath)  
           print '[' + texturepath + ']'  
           file.write(texturepath)  
           if itemVersion == 0x0002:  
                data = struct.pack(format, armour)  
                print '[' + repr(armour) + ']'  
                file.write(data)  
           print 'Finished... Closing...'  
           file.close()  
             
             
 ################################  
   
 #file = open(fileName, 'wb')  
   
 root = Tk()  
 root.title('ITEM Creator')  
   
 toplevel = tk.Toplevel(root)  
   
 toplevel.geometry('640x480')  
 toplevel.resizable(0,0)  
   
 toplevel.withdraw()  
   
 root.config(bg='black')  
 root.protocol("WM_DELETE_WINDOW", quit)  
   
 program = Program(root)  
   
 # Main Menu  
 menubar = Menu(root)  
 root.config(menu=menubar)  
 # Options Menu  
 optionsmenu = Menu(menubar, tearoff=0)  
 optionsmenu.add_command(label='Data to text field', command=program.printValues)  
 optionsmenu.add_separator()  
 optionsmenu.add_command(label='Quit', command=quit)  
 menubar.add_cascade(label='Options', menu=optionsmenu)  
 # Help Menu  
 helpmenu = Menu(menubar, tearoff=0)  
 helpmenu.add_command(label='About', command=about)  
 menubar.add_cascade(label='Help', menu=helpmenu)  
 # About  
 abo = Tk()  
 abo.title('About')  
 abo.config(bg='black')  
 abo.protocol('WM_DELETE_WINDOW', hideabout)  
 aviabo = About(abo)  
 hideabout()  
   
 root.mainloop()  

It's not optimised, just quick and dirty. But that's what I use Python for. I only bother polishing the stuff that matters: the C++ that runs the game.

Saturday 17 March 2012

Ship in a bottle

Ever since I was a kid, I've had this little yacht in a bottle that I bought from a man at Sydney harbour. As a cool little bit of loot for the game, I decided to model it and put it in. It'll serve as exotic loot that will sell for a nice price, or decorate the player's home. Or maybe it will be a charm of some kind - granting the player a passive benefit.


I also completed my new low-poly musket model. A video is here, and an image below.


Wednesday 14 March 2012

Bicorne models



Yesterday I did a lot of modelling. I created a model bicorne, then ruthlessly cut down the vertices to make it quite low-poly. I kept this as the simple version of the hat, then I proceeded to create a decorated bicorne which has a badge and flower. Within the game these decorated bicornes will be worn by officers, sergeants, etc of the various factions and will be of different colours and designs. Undecorated bicornes will be common attire for citizens and soldiers.

I loaded all the models into the inventory. See a video here.

Next on my list of things to create is a low-poly musket, then I may have a stab at a tricorne.

Thursday 8 March 2012

New Models

I went on a bit of a modelling spree after successfully making and texturing a 3D pie. I went on to make an apple, a helmet and a musket. Although my creations reek of 'programmer art', they're all I have to go on right now. They're good place holders, and I'm quite proud of my pie. The rest I consider to be good first attempts.


They've served to fatten up my inventory a little already, and I will soon make more.

Tuesday 6 March 2012

Inventory

The foundations of my inventory system are complete, and mostly working as I want them to. Here's a video. Thanks very much to the people over at www.opengameart.org for the 3D models.

Friday 2 March 2012

Newest Feature: Map Creator

I worked hard all of today to fix my Map Creator. It's come back in the form of a chunk creator, that allows for 128 cubes to be placed and saved in an XML file for loading later on. Of particular interest is the spinning 3D cube that displays what cube material you have selected.

Here's the video. Hope you like it :D I certainly do ;)

Tuesday 28 February 2012

About Tyran



I created this blog to track the progress of my hobby game project: Tyran. It serves as a simple development diary and a place I can direct those interested in Tyran to for more information.

Tyran is written in C++ with the Irrlicht engine and aims to be an open world RPG that will explore a unique fantasy world of my own creation. The world of Tyran has its foundations in the imagination of my brothers' minds as children, and is therefore quite original. It will probably turn out single player only initially, and work on Linux and Windows. Multiplayer may be added at a later stage, but it isn't a priority.

Progress Videos

I often create a video of Tyran when I improve it or add a feature. These are in order from latest to oldest:

Alpha 1.9.4 Demo - February 23, 2012 - Demonstrates cube building and digging, along with combat against a basic jelly AI.

Jelly Attack - February 22, 2012 -Shows jelly AI coming at the player to attack.

Testing Video - February 21, 2012 - Shows some simple testing.

Demo - February 20, 2012 - Gameplay demo.