From a85c3ca1ff34775f2fc93013306dec21b34b0359 Mon Sep 17 00:00:00 2001
From: Stijn Buys <ingar@osirion.org>
Date: Fri, 17 Sep 2010 23:05:58 +0000
Subject: Initial inventory loading, ships docking ships

---
 src/client/Makefile.am          |   4 +-
 src/client/inventorylistview.cc |  39 +++++++++++
 src/client/inventorylistview.h  |  27 ++++++++
 src/core/commandbuffer.cc       |  26 +++++++-
 src/core/entity.cc              |  20 ++++++
 src/core/entity.h               |   7 +-
 src/core/item.h                 |  16 ++++-
 src/core/parser.cc              |   2 +-
 src/filesystem/inifile.cc       |  21 ++++++
 src/filesystem/inifile.h        |   8 +++
 src/game/base/Makefile.am       |   4 +-
 src/game/base/cargo.cc          |  38 +++++++++++
 src/game/base/cargo.h           |  27 ++++++++
 src/game/base/commodity.cc      |  28 --------
 src/game/base/commodity.h       |  25 --------
 src/game/base/game.cc           | 139 +++++++++++++++++++++++++++++++++++-----
 src/game/base/planet.cc         |   3 +-
 src/game/base/ship.cc           |  31 +++++++++
 src/game/base/ship.h            |   2 +
 src/game/base/station.cc        |   2 +-
 20 files changed, 388 insertions(+), 81 deletions(-)
 create mode 100644 src/client/inventorylistview.cc
 create mode 100644 src/client/inventorylistview.h
 create mode 100644 src/game/base/cargo.cc
 create mode 100644 src/game/base/cargo.h
 delete mode 100644 src/game/base/commodity.cc
 delete mode 100644 src/game/base/commodity.h

diff --git a/src/client/Makefile.am b/src/client/Makefile.am
index 741f5a3..ddc78a6 100644
--- a/src/client/Makefile.am
+++ b/src/client/Makefile.am
@@ -8,7 +8,7 @@ noinst_LTLIBRARIES = libclient.la
 endif
 
 libclient_la_SOURCES = action.cc buymenu.cc chat.cc client.cc clientext.cc \
-	entitymenu.cc hud.cc infowidget.cc input.cc inventorymenu.cc joystick.cc key.cc \
+	entitymenu.cc hud.cc infowidget.cc input.cc inventorylistview.cc inventorymenu.cc joystick.cc key.cc \
 	keyboard.cc map.cc notifications.cc playerview.cc soundext.cc targeticonbutton.cc \
 	targets.cc trademenu.cc video.cc worldview.cc
 
@@ -17,7 +17,7 @@ libclient_la_CFLAGS = $(LIBSDL_CFLAGS) $(GL_CFLAGS)
 libclient_la_LDFLAGS = -avoid-version -no-undefined $(GL_LIBS) $(LIBSDL_LIBS)
 
 noinst_HEADERS = action.h chat.h client.h clientext.h hud.h entitymenu.h \
-	input.h inventorymenu.h joystick.h key.h keyboard.h map.h notifications.h soundext.h \
+	input.h inventorylistview.h inventorymenu.h joystick.h key.h keyboard.h map.h notifications.h soundext.h \
 	targets.h video.h infowidget.h playerview.h worldview.h trademenu.h buymenu.h \
 	targeticonbutton.h
 
diff --git a/src/client/inventorylistview.cc b/src/client/inventorylistview.cc
new file mode 100644
index 0000000..656adfb
--- /dev/null
+++ b/src/client/inventorylistview.cc
@@ -0,0 +1,39 @@
+/*
+   client/inventorylistview.cc
+   This file is part of the Osirion project and is distributed under
+   the terms and conditions of the GNU General Public License version 2
+*/
+
+#include "client/inventorylistview.h"
+#include "ui/listitem.h"
+
+namespace client {
+
+InventoryListView::InventoryListView(ui::Widget *parent) : ui::ListView (parent)
+{
+	set_inventory(0, 0);
+}
+
+void InventoryListView::set_inventory(core::Inventory *inventory, core::InfoType *info_type)
+{
+	remove_children();
+	
+	if (!inventory || !info_type) {
+		return;
+	}
+	
+	for (core::Inventory::Items::const_iterator it = inventory->items().begin(); it != inventory->items().end(); it++) {
+		core::Item *item = (*it);
+	
+		if (item->info() && item->info()->type() == info_type) {
+			ui::ListItem *listitem = 0;	
+			listitem = new ui::ListItem(this, item->info()->name().c_str());
+			listitem->set_height(listitem->font()->height() * 2.0f);
+			listitem->set_info(item->info());
+		}
+	}
+	
+	event_resize();
+}
+
+} // namespace client
\ No newline at end of file
diff --git a/src/client/inventorylistview.h b/src/client/inventorylistview.h
new file mode 100644
index 0000000..82a9cc4
--- /dev/null
+++ b/src/client/inventorylistview.h
@@ -0,0 +1,27 @@
+/*
+   client/inventorylistview.h
+   This file is part of the Osirion project and is distributed under
+   the terms and conditions of the GNU General Public License version 2
+*/
+
+#ifndef __INCLUDED_CLIENT_INVENTORYLISTVIEW_H__
+#define __INCLUDED_CLIENT_INVENTORYLISTVIEW_H__
+
+#include "core/info.h"
+#include "core/inventory.h"
+#include "ui/listview.h"
+
+
+namespace client {
+	
+class InventoryListView : public ui::ListView {
+public:
+	InventoryListView(ui::Widget *parent = 0);
+	~InventoryListView();
+	
+	void set_inventory(core::Inventory *inventory, core::InfoType *info_type);
+};
+
+} // namespace client
+
+#endif //__INCLUDED_CLIENT_INVENTORYLISTVIEW_H__
\ No newline at end of file
diff --git a/src/core/commandbuffer.cc b/src/core/commandbuffer.cc
index 3c7fc35..40971cc 100644
--- a/src/core/commandbuffer.cc
+++ b/src/core/commandbuffer.cc
@@ -116,6 +116,22 @@ void func_list_ent(std::string const &args)
 	Entity::list();
 }
 
+void func_list_inventory(std::string const &args)
+{
+	unsigned long id;
+	std::istringstream argstream(args);
+	if (argstream >> id) {
+		Entity *entity = Entity::find(id);
+		if (entity) {
+			entity->list_inventory();
+		} else {
+			con_print << "Could not find entity with id " << id << std::endl;
+		}		
+	} else {
+		con_print << "usage: list_inventory [entity id]" <<  std::endl;
+	}
+}
+
 void func_list_zone(std::string const &args)
 {
 	Zone *zone = Zone::search(args);
@@ -142,7 +158,7 @@ void func_set(std::string const &args)
 	std::istringstream argstream(args);
 	std::string varname;
 	if (!(argstream >> varname)) {
-		con_print << "Variable name expected!"  << std::endl;
+		con_print << "usage: set [variable name]" <<  std::endl;
 		return;
 	}
 
@@ -174,7 +190,7 @@ void func_toggle(std::string const &args)
 	std::istringstream argstream(args);
 	std::string varname;
 	if (!(argstream >> varname)) {
-		con_print << "Variable name expected!"  << std::endl;
+		con_print << "usage: toggle [variable name]" <<  std::endl;
 		return;
 	}
 
@@ -242,6 +258,9 @@ void CommandBuffer::init()
 	func = Func::add("list_info", (FuncPtr)func_list_info);
 	func->set_info("list info records");
 
+	func = Func::add("list_inventory", (FuncPtr)func_list_inventory);
+	func->set_info("[entity id] list entity inventories");
+
 	func = Func::add("list_var", (FuncPtr)func_list_var);
 	func->set_info("list variables");
 
@@ -249,7 +268,7 @@ void CommandBuffer::init()
 	func->set_info("list zones");
 
 	Func::add("list_model", (FuncPtr) func_list_model);
-	func->set_info("list models");
+	func->set_info("list 3d models");
 
 	Func::add("list_module", (FuncPtr) func_list_module);
 	func->set_info("list game modules");
@@ -282,6 +301,7 @@ void CommandBuffer::shutdown()
 	Func::remove("list_var");
 	Func::remove("list_func");
 	Func::remove("list_info");
+	Func::remove("list_inventories");
 	Func::remove("list_ent");
 	Func::remove("list_model");
 	Func::remove("list_module");
diff --git a/src/core/entity.cc b/src/core/entity.cc
index fdcce59..538aecb 100644
--- a/src/core/entity.cc
+++ b/src/core/entity.cc
@@ -401,6 +401,26 @@ void Entity::remove_menu(std::string const &label)
 	}
 }
 
+void Entity::list_inventory() const
+{
+	con_print << "  ^B" << name() << "^N ";
+	if (!entity_inventory) {
+		con_print << "no inventory availble" << std::endl;
+		return;
+	}
+	con_print << "inventory" << std::endl;
+	
+	for (Inventory::Items::const_iterator it = entity_inventory->items().begin(); it != entity_inventory->items().end(); it++) {
+		Item *item = (*it);
+		con_print << " " 
+			  << " ^B" << std::setw(4) << item->info()->id()
+			  << " ^N" << (item->info()->type() ? item->info()->type()->label() : "NULL")
+			  << " ^N" << item->info()->label()
+			  << " amount " << item->amount() << std::endl;
+	}
+	
+}
+
 /* ---- class EntityDynamic ---------------------------------------- */
 
 EntityDynamic::EntityDynamic() : Entity()
diff --git a/src/core/entity.h b/src/core/entity.h
index fea784a..8bf637d 100644
--- a/src/core/entity.h
+++ b/src/core/entity.h
@@ -189,6 +189,9 @@ public:
 		return entity_destroyed;
 	}
 
+	/// list inventory, if available, to console
+	void list_inventory() const;
+
 	/* ---- mutators -------------------------------------------------- */
 
 	/// assign entity color
@@ -252,10 +255,10 @@ public:
 		entity_radius = radius;
 	}
 
-	/* ---- actors ---------------------------------------------------- */
+/* ---- actors ---------------------------------------------------- */
 
 	/// called when the entity received a docking request
-	virtual void dock(core::Entity *entity);
+	virtual void dock(Entity *entity);
 
 	/// set flags
 	inline void set_flag(Flags flag) {
diff --git a/src/core/item.h b/src/core/item.h
index 397d259..f1d6bb5 100644
--- a/src/core/item.h
+++ b/src/core/item.h
@@ -41,7 +41,7 @@ public:
 	  * @brief flags
 	  */
 	 inline int flags() const { return item_flags; }
-	 
+	  
 	/* ---- mutators ----------------------------------------------- */
 
 	/**
@@ -49,6 +49,20 @@ public:
 	 */
 	 void set_amount(const int amount);
 	 
+	/**
+	  * @brief set specified flags
+	  */
+	inline void set_flag(Flags flag) {
+		item_flags |= flag;
+	}
+
+	/**
+	  * @brief unset specified flags
+	  */
+	inline void unset_flag(Flags flag) {
+		item_flags &= ~flag;
+	}
+	
 private:
 	const Info			*item_info;
 	int 				item_amount;
diff --git a/src/core/parser.cc b/src/core/parser.cc
index 7ef44d9..8018bf7 100644
--- a/src/core/parser.cc
+++ b/src/core/parser.cc
@@ -65,7 +65,7 @@ bool Parser::got_entity_key(filesystem::IniFile &inifile, core::Entity *entity)
 		entity->info()->add_text(strval);
 		return true;
 
-	} else if (inifile.got_key_string("label", strval)) {
+	} else if (inifile.got_key_label("label", strval)) {
 		entity->set_label(strval);
 		return true;
 
diff --git a/src/filesystem/inifile.cc b/src/filesystem/inifile.cc
index e9ab283..8cf186c 100644
--- a/src/filesystem/inifile.cc
+++ b/src/filesystem/inifile.cc
@@ -159,6 +159,17 @@ bool IniFile::got_key_string(const char * keylabel, std::string & valuestring)
 	}
 }
 
+bool IniFile::got_key_label(const char * keylabel, std::string & labelstring)
+{
+	if (last_read_was_key && (key_current.compare(keylabel) == 0)) {
+		labelstring.assign(value_current);
+		aux::to_label(labelstring);
+		return true;
+	} else {
+		return false;
+	}
+}
+
 bool IniFile::got_key_vector3f(const char * keylabel, math::Vector3f & v)
 {
 	if (last_read_was_key && (key_current.compare(keylabel) == 0)) {
@@ -298,6 +309,16 @@ void IniFile::unknown_section() const
 	con_warn << name() << " unknown section '" << section() << "' at line " << line() << std::endl;
 }
 
+void IniFile::unknown_error(const char *text) const
+{
+	con_warn << name() << " " << (text && text[0] ? text : "unknown error") << " at line " << line() << std::endl;
+}
+
+void IniFile::unknown_error(const std::string &text) const
+{
+	con_warn << name() << " " << text << " at line " << line() << std::endl;
+}
+
 void IniFile::close()
 {
 	inifile_stream.close();
diff --git a/src/filesystem/inifile.h b/src/filesystem/inifile.h
index e5423aa..4b94dcd 100644
--- a/src/filesystem/inifile.h
+++ b/src/filesystem/inifile.h
@@ -72,6 +72,9 @@ public:
 	/// check if the last read key=value pair matches keylabel and store the value in valuestring
 	bool got_key_string(const char * keylabel, std::string & valuestring);
 
+	/// check if the last read key=value pair matches keylabel and store the value in valuestring, converted to label
+	bool got_key_label(const char * keylabel, std::string & labelstring);
+	
 	bool got_key_color(const char * keylabel, math::Color & color);
 
 	bool got_key_float(const char * keylabel, float & f);
@@ -97,6 +100,11 @@ public:
 
 	/// print a default unkown section error
 	void unknown_section() const;
+	
+	/// print a generic error message
+	void unknown_error(const char *text = 0) const;
+	
+	void unknown_error(const std::string &text) const;
 
 	/// return true of the ini file is open for reading
 	inline bool is_open() {
diff --git a/src/game/base/Makefile.am b/src/game/base/Makefile.am
index c3625a0..f7fd52e 100644
--- a/src/game/base/Makefile.am
+++ b/src/game/base/Makefile.am
@@ -2,8 +2,8 @@ INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/game
 METASOURCES = AUTO
 libbase_la_LDFLAGS = -avoid-version
 noinst_LTLIBRARIES = libbase.la
-libbase_la_SOURCES = collision.cc commodity.cc game.cc jumppoint.cc navpoint.cc physics.cc \
+libbase_la_SOURCES = collision.cc cargo.cc game.cc jumppoint.cc navpoint.cc physics.cc \
 	planet.cc racetrack.cc ship.cc shipdealer.cc shipmodel.cc star.cc station.cc
-noinst_HEADERS = game.h collision.h commodity.h jumppoint.h navpoint.h physics.h planet.h \
+noinst_HEADERS = game.h collision.h cargo.h jumppoint.h navpoint.h physics.h planet.h \
 	racetrack.h ship.h shipdealer.h shipmodel.h star.h station.h
 
diff --git a/src/game/base/cargo.cc b/src/game/base/cargo.cc
new file mode 100644
index 0000000..258aecf
--- /dev/null
+++ b/src/game/base/cargo.cc
@@ -0,0 +1,38 @@
+/*
+   base/cargo.cc
+   This file is part of the Osirion project and is distributed under
+   the terms and conditions of the GNU General Public License version 2
+*/
+
+#include "base/game.h"
+#include "base/cargo.h"
+#include "auxiliary/functions.h"
+#include "sys/sys.h"
+
+namespace game
+{
+
+/* ---- class Cargo -------------------------------------------- */
+
+core::InfoType *Cargo::cargo_infotype = 0;
+
+Cargo::Cargo() : core::Info(cargo_infotype)
+{
+}
+
+Cargo::~Cargo()
+{
+}
+
+Cargo *Cargo::find(const std::string & label)
+{
+	if (!label.size()) {
+		return 0;
+	}
+	
+	return (Cargo *) core::Info::find(cargo_infotype, label);
+}
+
+
+} // namespace game
+
diff --git a/src/game/base/cargo.h b/src/game/base/cargo.h
new file mode 100644
index 0000000..808b4c0
--- /dev/null
+++ b/src/game/base/cargo.h
@@ -0,0 +1,27 @@
+/*
+   base/cargo.h
+   This file is part of the Osirion project and is distributed under
+   the terms and conditions of the GNU General Public License version 2
+*/
+
+#ifndef __INCLUDED_BASE_CARGO_H__
+#define __INCLUDED_BASE_CARGO_H__
+
+#include "core/info.h"
+
+namespace game
+{
+class Cargo : public core::Info {
+
+public:
+	Cargo();
+	~Cargo();
+
+	static core::InfoType *cargo_infotype;
+	
+	static Cargo *find(const std::string & label);
+};
+
+} // namespace game
+
+#endif // __INCLUDED_BASE_CARGO_H__
diff --git a/src/game/base/commodity.cc b/src/game/base/commodity.cc
deleted file mode 100644
index 4f238be..0000000
--- a/src/game/base/commodity.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
-   base/commodity.cc
-   This file is part of the Osirion project and is distributed under
-   the terms and conditions of the GNU General Public License version 2
-*/
-
-#include "base/game.h"
-#include "base/commodity.h"
-#include "auxiliary/functions.h"
-#include "sys/sys.h"
-
-namespace game
-{
-
-/* ---- class Commodity -------------------------------------------- */
-
-core::InfoType *Commodity::commodity_infotype = 0;
-
-Commodity::Commodity() : core::Info(commodity_infotype)
-{
-}
-
-Commodity::~Commodity()
-{
-}
-
-} // namespace game
-
diff --git a/src/game/base/commodity.h b/src/game/base/commodity.h
deleted file mode 100644
index b889749..0000000
--- a/src/game/base/commodity.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
-   base/commodity.h
-   This file is part of the Osirion project and is distributed under
-   the terms and conditions of the GNU General Public License version 2
-*/
-
-#ifndef __INCLUDED_BASE_COMMODITY_H__
-#define __INCLUDED_BASE_COMMODITY_H__
-
-#include "core/info.h"
-
-namespace game
-{
-class Commodity : public core::Info {
-
-public:
-	Commodity();
-	~Commodity();
-
-	static core::InfoType *commodity_infotype;
-};
-
-} // namespace game
-
-#endif // __INCLUDED_BASE_COMMODITY_H__
diff --git a/src/game/base/game.cc b/src/game/base/game.cc
index 128ae7c..667a4c1 100644
--- a/src/game/base/game.cc
+++ b/src/game/base/game.cc
@@ -15,8 +15,8 @@
 #include "filesystem/filesystem.h"
 #include "filesystem/inifile.h"
 #include "base/game.h"
+#include "base/cargo.h"
 #include "base/collision.h"
-#include "base/commodity.h"
 #include "base/navpoint.h"
 #include "base/jumppoint.h"
 #include "base/planet.h"
@@ -208,7 +208,7 @@ void Game::func_buy(core::Player *player, const std::string &args)
 	} else if (typestr.compare("cargo") == 0) {
 		player->send("Buying cargo is not supported");
 	} else {
-		player->send("unkown item type '" + typestr + "'");
+		player->send("Unkown item type '" + typestr + "'");
 	}
 
 	return;
@@ -228,10 +228,47 @@ void Game::func_launch(core::Player *player, std::string const &args)
 
 	assert(player->view()->zone() == player->control()->zone());
 
-	Ship *ship = static_cast<Ship *>(player->control());
-	ship->shutdown_physics();
 	core::Entity *dock = player->view();
+	
+	if (dock->moduletype() == ship_enttype) {
+		
+		switch(static_cast<Ship *>(dock)->state()) {
 
+			case core::Entity::Normal:
+			case core::Entity::Docked:
+				break;
+			
+			case core::Entity::NoPower:
+				player->send("^BCan not launch while carrier has no power!");	
+				return;
+				break;
+			
+			case core::Entity::ImpulseInitiate:
+			case core::Entity::Impulse:
+				player->send("^BCan not launch while carrier is using impulse engines!");
+				return;
+				break;
+				
+			case core::Entity::JumpInitiate:
+			case core::Entity::Jump:
+				player->send("^BCan not launch while carrier is jumping through hyperspace!");	
+				return;
+				break;
+			
+			default:
+				if (other_ship->state() != ) {
+					player->send("^BCan not launch from carrier!");	
+					return;
+				}
+				break;
+		}
+	}
+	
+	assert(player->control()->moduletype() == ship_enttype);
+		
+	Ship *ship = static_cast<Ship *>(player->control());
+	ship->shutdown_physics();
+	
 	if (dock->type() == core::Entity::Globe)
 		ship->get_location().assign(dock->location() + (dock->axis().forward() *(planet_safe_distance + ship->radius() + dock->radius())));
 	else
@@ -712,12 +749,18 @@ bool Game::load_menus(core::Entity *entity, const std::string &menufilename)
 		return false;
 	}
 
+	
+
+	
 	filesystem::IniFile inifile;
 
 	std::string strval;
 	MenuDescription *menu_dealer = 0;
 	ButtonDescription *button = 0;
-	ShipDealer *shipdealer = 0;
+	ShipDealer *shipdealer = 0;	
+	
+	core::Inventory *inventory = 0;
+	core::Item *item = 0;
 
 	inifile.open(menufilename);
 
@@ -725,7 +768,11 @@ bool Game::load_menus(core::Entity *entity, const std::string &menufilename)
 		while (inifile.getline()) {
 
 			if (inifile.got_section()) {
+				
+				item = 0;
+				
 				if (inifile.got_section("dealer")) {
+					// TODO replace [dealer] section with individual [ship] sections
 					// dealer menu
 					if (!menu_dealer) {
 						menu_dealer = new MenuDescription();
@@ -739,6 +786,11 @@ bool Game::load_menus(core::Entity *entity, const std::string &menufilename)
 							static_cast<Station *>(entity)->set_shipdealer(shipdealer);
 						}
 					}
+				
+				} else if (inifile.got_section("cargo")) {
+					
+				} else if (inifile.got_section("ship")) {
+					
 				} else {
 					inifile.unknown_section();
 				}
@@ -759,16 +811,73 @@ bool Game::load_menus(core::Entity *entity, const std::string &menufilename)
 							button->set_info(model);
 							button->set_alignment(ButtonDescription::Left);
 							menu_dealer->add_button(button);
+						} else {
+							std::string msg("unknown ship type '");
+							msg.append(strval);
+							msg.append("'");
+							inifile.unknown_error(msg);
 						}
 					} else {
 						inifile.unkown_key();
 					}
 
-				}
+				} else if (inifile.in_section("cargo")) {
+					
+					if (inifile.got_key_label("label", strval)) {
+						Cargo *cargo = Cargo::find(strval);
+						if (cargo) {
+							if (!inventory) {
+								inventory = new core::Inventory();
+							}
+							item = inventory->find(cargo);
+							if (!item) {
+								item = new core::Item(cargo);
+								item->set_amount(-1);
+								inventory->add(item);
+							}
+						} else {
+							std::string msg("unkown cargo type '");
+							msg.append(strval);
+							msg.append("'");
+							inifile.unknown_error(msg);
+						}
+						
+					} else {
+						inifile.unkown_key();
+					}
+					
+				} else if (inifile.in_section("ship")) {
+					
+					if (inifile.got_key_label("label", strval)) {
+						ShipModel *shipmodel = ShipModel::find(strval);
+						if (shipmodel) {
+							if (!inventory) {
+								inventory = new core::Inventory();
+							}
+							item = inventory->find(shipmodel);
+							if (!item) {
+								item = new core::Item(shipmodel);
+								item->set_amount(-1);
+								inventory->add(item);
+							}
+						} else {
+							std::string msg("unknown ship type '");
+							msg.append(strval);
+							msg.append("'");
+							inifile.unknown_error(msg);
+						}
+						
+					} else {
+						inifile.unkown_key();
+					}
+				}				
 			}
 		}
 
 	}
+	
+	if (inventory)
+		entity->set_inventory(inventory);
 
 	MenuDescription *menu_main = new MenuDescription();
 	menu_main->set_label("main");
@@ -810,7 +919,7 @@ bool Game::load_menus(core::Entity *entity, const std::string &menufilename)
 bool Game::load_commodities()
 {
 	// initialize commodities InfoType
-	Commodity::commodity_infotype = new core::InfoType("cargo");
+	Cargo::cargo_infotype = new core::InfoType("cargo");
 	
 	filesystem::IniFile cargoini;
 	cargoini.open("cargo");
@@ -823,28 +932,28 @@ bool Game::load_commodities()
 	
 	size_t count = 0;
 	
-	Commodity *commodity = 0;
+	Cargo *cargo = 0;
 	std::string str;
 	
 	while (cargoini.getline()) {
 		if (cargoini.got_key()) {
 		
 			if (cargoini.section().compare("cargo") == 0) {
-				if (cargoini.got_key_string("label", str)) {
-					commodity->set_label(std::string(str));
+				if (cargoini.got_key_label("label", str)) {
+					cargo->set_label(std::string(str));
 					count++;
 					continue;
 					
 				} else if (cargoini.got_key_string("name", str)) {
-					commodity->set_name(str);
+					cargo->set_name(str);
 					continue;
 
 				} else if (cargoini.got_key_string("info", str)) {
-					commodity->add_text(str);
+					cargo->add_text(str);
 					continue;
 					
 				} else if (cargoini.got_key_string("model", str)) {
-					commodity->set_modelname(str);
+					cargo->set_modelname(str);
 					continue;
 				
 				} else {
@@ -855,7 +964,7 @@ bool Game::load_commodities()
 		} else if (cargoini.got_section()) {
 		
 			if (cargoini.got_section("cargo")) {
-				commodity = new Commodity();
+				cargo = new Cargo();
 				
 			} else if (cargoini.got_section()) {
 				cargoini.unknown_section();
@@ -898,7 +1007,7 @@ bool Game::load_ships()
 	while (shipsini.getline()) {
 		if (shipsini.got_key()) {
 			if (shipsini.section().compare("ship") == 0) {
-				if (shipsini.got_key_string("label", str)) {
+				if (shipsini.got_key_label("label", str)) {
 					shipmodel->set_label(str);
 					count++;
 					continue;
diff --git a/src/game/base/planet.cc b/src/game/base/planet.cc
index 380ca02..ca213af 100644
--- a/src/game/base/planet.cc
+++ b/src/game/base/planet.cc
@@ -49,13 +49,14 @@ void Planet::dock(core::Entity *entity)
 
 	Ship * ship = static_cast<Ship *>(entity);
 
+	// fixed 50 km docking radius
 	if (math::distance(location(), ship->location()) > radius() + ship->radius() + 50.0f) {
 		if (ship->owner())
 			ship->owner()->send("Planet out of range");
 		return;
 	}
 
-	ship->get_location().assign(entity->location());
+	ship->get_location().assign(location());
 	ship->set_state(core::Entity::Docked);
 
 	if (ship->owner() && ship->owner()->control() == ship) {
diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc
index 7edc183..0da57ab 100644
--- a/src/game/base/ship.cc
+++ b/src/game/base/ship.cc
@@ -82,6 +82,37 @@ void Ship::reset()
 	current_target_strafe = 0.0f;
 	current_target_afterburner = 0.0f;
 }
+
+// this is called if another shuo wants to dock this ship
+void Ship::dock(Entity *entity)
+{
+	if (!flag_is_set(core::Entity::Dockable))
+		return;
+	
+	if (entity->moduletype() != ship_enttype)
+		return;
+
+	Ship *other_ship = static_cast<Ship *>(entity);
+
+	if (math::distance(location(), other_ship->location()) > radius() + other_ship->radius()) {
+		if (other_ship->owner())
+			other_ship->owner()->send("Target out of range");
+		return;
+	}
+
+	other_ship->get_location().assign(location());
+	other_ship->set_state(core::Entity::Docked);
+
+	if (other_ship->owner() && other_ship->owner()->control() == other_ship) {
+		other_ship->owner()->set_view(this);
+		if (owner()) {
+			other_ship->owner()->send("^BDocking at " + owner()->name() + "^B's " + name());
+		} else {
+			other_ship->owner()->send("^BDocking at " + name());
+		}
+	}
+}
+	
 void Ship::func_impulse()
 {
 	if (entity_state == core::Entity::Impulse) {
diff --git a/src/game/base/ship.h b/src/game/base/ship.h
index e1b8b1d..f66bb66 100644
--- a/src/game/base/ship.h
+++ b/src/game/base/ship.h
@@ -51,6 +51,8 @@ public:
 
 	/// toggle jump drive activation
 	void func_jump(std::string const & args);
+	
+	virtual void dock(Entity *entity);
 
 private:
 	JumpPoint *find_closest_jumppoint();
diff --git a/src/game/base/station.cc b/src/game/base/station.cc
index fb548bb..83897cd 100644
--- a/src/game/base/station.cc
+++ b/src/game/base/station.cc
@@ -49,7 +49,7 @@ void Station::dock(core::Entity *entity)
 		return;
 	}
 
-	ship->get_location().assign(entity->location());
+	ship->get_location().assign(location());
 	ship->set_state(core::Entity::Docked);
 
 	if (ship->owner() && ship->owner()->control() == ship) {
-- 
cgit v1.2.3