Help with List field in a type

BlitzMax Forums/BlitzMax Beginners Area/Help with List field in a type

okee(Posted 2016) [#1]
I'm trying to find examples of adding Types to a list field in another type but just not having any luck at the moment

The code is listed below, just as an example to refer to.
Basically I just want to add say 2 weapons to first ship , 3 weapons to the next etc

Also how do you reference the fields of a type that are in a list when you use the List.First() method

Thanks a lot


Strict

Graphics 1024,768

Global ShipList:TList = CreateList()

' ship type
Type TShip
		
	Field Name:String
	Field Fuel:Int
	Field Weapons:TList = CreateList() ' list of weapons each ship can have
	
	'create a ship
	Function Build(ShipName:String, ShipFuel:Int)
		Local NewShip:TShip
		
		NewShip = New TShip
		NewShip.Name = ShipName
		NewShip.Fuel = ShipFuel
		ShipList.AddLast(NewShip)			
		
	End Function
	
	' add a weapon , not sure if this works
	Method AddWeapon(WeaponName:String, WeaponPower:Int)
		
		Local NewWeapon:TWeapon
		
		NewWeapon = New TWeapon
		NewWeapon.Name = WeaponName
		NewWeapon.Power = WeaponPower
		Weapons.Addlast(NewWeapon)
	
	End Method			
			
End Type

' weapons type
Type TWeapon

	Field Name:String
	Field Power:Int
	
End Type

' create the ships
CreateShips()

' main loop
While Not KeyHit(KEY_ESCAPE)
	Cls

	Local y:Int = 12
	Local s:TShip
		
	' print a list of the ships
	For s = EachIn ShipList
		DrawText ("Ship name: " + s.Name + " - " + "Ship Fuel: " + s.Fuel,20,y)
		y = y + 12
	Next	

	Flip
Wend	

' create new ships
Function CreateShips()
	
	Local s:TShip
	'Local w:TWeapon
	'Think you have to use the TShip name otherwise gives an error
	TShip.Build("Fighter",80)
	TShip.Build("Cruiser",34)
	TShip.Build("Transporter",64)
	TShip.Build("Scout",74)
	
	' I want to add 2 weapons to the first ship, 3 to the second and 1 to the 3rd ship
	
	' add weapons to the first ship
	'If ShipList.First() <> Null
	'	DrawText (ShipList.First().s.Name,10,200)		
		
	'EndIf
		
End Function




Brucey(Posted 2016) [#2]
Why not have TShip.Build() return an instance of the ship you just made. Then you can call newship.AddWeapon()...
eg
Function Build:TShip(ShipName:String, ShipFuel:Int)
...
    Return NewShip
End Function


Function CreateShips()
...
    Local s:TShip = TShip.Build("Fighter",80)
    s.AddWeapon(...)
...
End Function



Derron(Posted 2016) [#3]
okee:

Also how do you reference the fields of a type that are in a list when you use the List.First() method


Use:
'general: TMyType( list.First() ).fieldName

TShip(shipList).AddWeapon("Chicken Thrower", 1)


This is needed as "first()" returns an "Object". Objects do not know about a TShips functions or variables. By casting it to the type "TShip" you tell the compiler that you know that this First()-object is of type "TShip". If this is _not_ the case, your app will crash on that line (because it accesses something which does not exist).

Instead of "First()" you also could use "TShip(shipListValueAtIndex(0))".


Another hint:
if you do not add weapons that often, you might use less memory with arrays (TWeapon[]). Of course removing a weapon then benefits from a rebuilding of that array (loop over existing ones, add them to a new array - and at the end, assign this new array to the variable holding the old one)

one possible approach:
Weapons[i] = null 'remove weapon at desired index
local newWeapons:TWeapons[]
For local w:TWeapon = eachIn Weapons
  if Weapons[i] then newWeapons :+ [w]
Next
Weapons = newWeapons


Of course it is also possible to use "array slices" (array = array[start ...entry] + array[entry+1 .. end]).


bye
Ron


Midimaster(Posted 2016) [#4]
This is another way to find and manipulate ships after they are already created. The function searches for a ship's name and return the ship as an object:

Type TShip
		
	Field Name:String
	Field Fuel:Int
	Field Weapons:TList = CreateList() ' list of weapons each ship can have
	
	Function Build(ShipName:String, ShipFuel:Int)
		Local NewShip:TShip= New TShip
		NewShip.Name = ShipName
		NewShip.Fuel = ShipFuel
		ShipList.AddLast(NewShip)			
	End Function
	
	Method AddWeapon(WeaponName:String, WeaponPower:Int)	
		Local NewWeapon:TWeapon = New TWeapon
		NewWeapon.Name = WeaponName
		NewWeapon.Power = WeaponPower
		Weapons.Addlast(NewWeapon)
	End Method			
			
	Function Find:TShip(ShipName:String)
		For Local Ship:TShip = EachIn ShipList
			If Ship.Name = ShipName
				Return Ship
			Endif
		Next
		Return NULL		
	End Function
End Type


With this you can do things like this:
TShip.Find("Fighter").AddWeapon("gun",100)
....
TShip.Find("Fighter").Fuel=0
....
ShipList.Remove TShip.Find("Fighter")



Derron(Posted 2016) [#5]
If a shipname is really unique, you would better have a TMap instead of a TList, as you then just do 'map.ValueForKey("Fighter")'.

If shipname is not unique, you end up iterating through all ships and returning the first hit ship.


bye
Ron


okee(Posted 2016) [#6]
Thanks guys, those tips helped a lot