瀏覽代碼

Merge pull request #889 from rathena/feature/random_start_point

Implemented Randomized Start Point
* Fixes #805.
* Character's will follow somewhat of the official method of a 'random' start point at their first login.
* Official servers use load balancing for setting the start point dynamically according to user count, whereas we at rAthena wanted to stay simple since we don't believe you guys will need this kind of load balancing for new characters.
Aleos 9 年之前
父節點
當前提交
994b406575
共有 7 個文件被更改,包括 137 次插入58 次删除
  1. 5 3
      conf/char_athena.conf
  2. 109 52
      src/char/char.c
  3. 6 1
      src/char/char.h
  4. 7 1
      src/common/mapindex.h
  5. 5 0
      src/common/mmo.h
  6. 1 1
      src/config/const.h
  7. 4 0
      src/map/atcommand.c

+ 5 - 3
conf/char_athena.conf

@@ -108,9 +108,11 @@ autosave_time: 60
 save_log: yes
 save_log: yes
 
 
 // Starting point for new characters
 // Starting point for new characters
-// Format: <map_name>,<x>,<y>
-start_point: iz_int,97,90
-start_point_pre: new_1-1,53,111
+// Format: <map_name>,<x>,<y>{:<map_name>,<x>,<y>...}
+// Max number of start points is MAX_STARTPOINT in char.h (default 5)
+// Location is randomly picked on character creation.
+start_point: iz_int,97,90:iz_int01,97,90:iz_int02,97,90:iz_int03,97,90:iz_int04,97,90
+start_point_pre: new_1-1,53,111:new_2-1,53,111:new_3-1,53,111:new_4-1,53,111:new_5-1,53,111
 
 
 // Starting items for new characters
 // Starting items for new characters
 // Max number of items is MAX_STARTITEM in char.c (default 32)
 // Max number of items is MAX_STARTITEM in char.c (default 32)

+ 109 - 52
src/char/char.c

@@ -53,13 +53,6 @@ static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
 // other is char_id
 // other is char_id
 unsigned int save_flag = 0;
 unsigned int save_flag = 0;
 
 
-#define MAX_STARTITEM 32
-struct startitem {
-	int nameid; //Item ID
-	int amount; //Number of items
-	int pos; //Position (for auto-equip)
-} start_items[MAX_STARTITEM+1];
-
 // Advanced subnet check [LuzZza]
 // Advanced subnet check [LuzZza]
 struct s_subnet {
 struct s_subnet {
 	uint32 mask;
 	uint32 mask;
@@ -1423,7 +1416,7 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 	char name[NAME_LENGTH];
 	char name[NAME_LENGTH];
 	char esc_name[NAME_LENGTH*2+1];
 	char esc_name[NAME_LENGTH*2+1];
 	uint32 char_id;
 	uint32 char_id;
-	int flag, k;
+	int flag, k, start_point_idx = rand() % charserv_config.start_point_count;
 
 
 	safestrncpy(name, name_, NAME_LENGTH);
 	safestrncpy(name, name_, NAME_LENGTH);
 	normalize_name(name,TRIM_CHARS);
 	normalize_name(name,TRIM_CHARS);
@@ -1475,7 +1468,7 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 		"'%d', '%d', '%s', '%d',  '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
 		"'%d', '%d', '%s', '%d',  '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
 		schema_config.char_db, sd->account_id , slot, esc_name, charserv_config.start_zeny, 48, str, agi, vit, int_, dex, luk,
 		schema_config.char_db, sd->account_id , slot, esc_name, charserv_config.start_zeny, 48, str, agi, vit, int_, dex, luk,
 		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
 		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
-		mapindex_id2name(charserv_config.start_point.map), charserv_config.start_point.x, charserv_config.start_point.y, mapindex_id2name(charserv_config.start_point.map), charserv_config.start_point.x, charserv_config.start_point.y) )
+		mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y, mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y) )
 	{
 	{
 		Sql_ShowDebug(sql_handle);
 		Sql_ShowDebug(sql_handle);
 		return -2; //No, stop the procedure!
 		return -2; //No, stop the procedure!
@@ -1487,7 +1480,7 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 		"'%d', '%d', '%s', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
 		"'%d', '%d', '%s', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
 		schema_config.char_db, sd->account_id , slot, esc_name, charserv_config.start_zeny, str, agi, vit, int_, dex, luk,
 		schema_config.char_db, sd->account_id , slot, esc_name, charserv_config.start_zeny, str, agi, vit, int_, dex, luk,
 		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
 		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
-		mapindex_id2name(charserv_config.start_point.map), charserv_config.start_point.x, charserv_config.start_point.y, mapindex_id2name(charserv_config.start_point.map), charserv_config.start_point.x, charserv_config.start_point.y) )
+		mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y, mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y) )
 	{
 	{
 		Sql_ShowDebug(sql_handle);
 		Sql_ShowDebug(sql_handle);
 		return -2; //No, stop the procedure!
 		return -2; //No, stop the procedure!
@@ -1496,8 +1489,8 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 	//Retrieve the newly auto-generated char id
 	//Retrieve the newly auto-generated char id
 	char_id = (int)Sql_LastInsertId(sql_handle);
 	char_id = (int)Sql_LastInsertId(sql_handle);
 	//Give the char the default items
 	//Give the char the default items
-	for (k = 0; k <= MAX_STARTITEM && start_items[k].nameid != 0; k ++) {
-		if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%hu', '%d', '%d', '%d')", schema_config.inventory_db, char_id, start_items[k].nameid, start_items[k].amount, start_items[k].pos, 1) )
+	for (k = 0; k <= MAX_STARTITEM && charserv_config.start_items[k].nameid != 0; k ++) {
+		if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%hu', '%hu', '%hu', '%d')", schema_config.inventory_db, char_id, charserv_config.start_items[k].nameid, charserv_config.start_items[k].amount, charserv_config.start_items[k].pos, 1) )
 			Sql_ShowDebug(sql_handle);
 			Sql_ShowDebug(sql_handle);
 	}
 	}
 
 
@@ -2636,10 +2629,18 @@ void char_set_defaults(){
 	charserv_config.log_inter = 1;	// loggin inter or not [devil]
 	charserv_config.log_inter = 1;	// loggin inter or not [devil]
 	charserv_config.char_check_db =1;
 	charserv_config.char_check_db =1;
 
 
-        //see const.h to change those default
-	charserv_config.start_point.map = mapindex_name2id(MAP_DEFAULT_NAME); 
-	charserv_config.start_point.x = MAP_DEFAULT_X;
-	charserv_config.start_point.y = MAP_DEFAULT_Y;
+	// See const.h to change the default values
+	charserv_config.start_point[0].map = mapindex_name2id(MAP_DEFAULT_NAME); 
+	charserv_config.start_point[0].x = MAP_DEFAULT_X;
+	charserv_config.start_point[0].y = MAP_DEFAULT_Y;
+	charserv_config.start_point_count = 0;
+
+	charserv_config.start_items[0].nameid = 1201;
+	charserv_config.start_items[0].amount = 1;
+	charserv_config.start_items[0].pos = 2;
+	charserv_config.start_items[1].nameid = 2301;
+	charserv_config.start_items[1].amount = 1;
+	charserv_config.start_items[1].pos = 16;
 
 
 	charserv_config.console = 0;
 	charserv_config.console = 0;
 	charserv_config.max_connect_user = -1;
 	charserv_config.max_connect_user = -1;
@@ -2653,6 +2654,96 @@ void char_set_defaults(){
 	charserv_config.default_map_y = 191;
 	charserv_config.default_map_y = 191;
 }
 }
 
 
+/**
+ * Split start_point configuration values.
+ * @param w2_value: Value from w2
+ */
+static void char_config_split_startpoint(char *w2_value)
+{
+	char *lineitem, **fields, config_name[20];
+	int i = 0, fields_length = 3 + 1;
+
+	memset(config_name, 0, sizeof(config_name));
+
+#ifdef RENEWAL
+	strcat(config_name, "start_point");
+#else
+	strcat(config_name, "start_point_pre");
+#endif
+
+	fields = (char **)aMalloc(fields_length * sizeof(char *));
+	if (fields == NULL)
+		return; // Failed to allocate memory.
+	lineitem = strtok(w2_value, ":");
+
+	while (lineitem != NULL) {
+		int n = sv_split(lineitem, strlen(lineitem), 0, ',', fields, fields_length, SV_NOESCAPE_NOTERMINATE);
+
+		if (n + 1 < fields_length) {
+			ShowDebug("%s: not enough arguments for %s! Skipping...\n", config_name, lineitem);
+			lineitem = strtok(NULL, ":"); //next lineitem
+			continue;
+		}
+		if (i > MAX_STARTPOINT)
+			ShowDebug("%s: too many start points, only %d are allowed! Ignoring parameter %s...\n", config_name, MAX_STARTPOINT, lineitem);
+		else {
+			charserv_config.start_point[i].map = mapindex_name2id(fields[1]);
+			if (!charserv_config.start_point[i].map) {
+				ShowError("Start point %s not found in map-index cache. Setting to default location.\n", charserv_config.start_point[i].map);
+				charserv_config.start_point[i].map = mapindex_name2id(MAP_DEFAULT_NAME);
+				charserv_config.start_point[i].x = MAP_DEFAULT_X;
+				charserv_config.start_point[i].y = MAP_DEFAULT_Y;
+			} else {
+				charserv_config.start_point[i].x = max(0, atoi(fields[2]));
+				charserv_config.start_point[i].y = max(0, atoi(fields[3]));
+			}
+			charserv_config.start_point_count++;
+		}
+		lineitem = strtok(NULL, ":"); //next lineitem
+		i++;
+	}
+	aFree(fields);
+}
+
+/**
+ * Split start_items configuration values.
+ * @param w2_value: Value from w2
+ */
+static void char_config_split_startitem(char *w2_value)
+{
+	char *lineitem, **fields, config_name[20];
+	int i = 0, fields_length = 3 + 1;
+
+	memset(config_name, 0, sizeof(config_name));
+
+	strcat(config_name, "start_items");
+
+	fields = (char **)aMalloc(fields_length * sizeof(char *));
+	if (fields == NULL)
+		return; // Failed to allocate memory.
+	lineitem = strtok(w2_value, ":");
+
+	while (lineitem != NULL) {
+		int n = sv_split(lineitem, strlen(lineitem), 0, ',', fields, fields_length, SV_NOESCAPE_NOTERMINATE);
+
+		if (n + 1 < fields_length) {
+			ShowDebug("%s: not enough arguments for %s! Skipping...\n", config_name, lineitem);
+			lineitem = strtok(NULL, ":"); //next lineitem
+			continue;
+		}
+		if (i > MAX_STARTITEM)
+			ShowDebug("%s: too many start items, only %d are allowed! Ignoring parameter %s...\n", config_name, MAX_STARTITEM, lineitem);
+		else {
+			charserv_config.start_items[i].nameid = max(0, atoi(fields[1]));
+			charserv_config.start_items[i].amount = max(0, atoi(fields[2]));
+			charserv_config.start_items[i].pos = max(0, atoi(fields[3]));
+		}
+		lineitem = strtok(NULL, ":"); //next lineitem
+		i++;
+	}
+	aFree(fields);
+}
+
 bool char_config_read(const char* cfgName, bool normal){
 bool char_config_read(const char* cfgName, bool normal){
 	char line[1024], w1[1024], w2[1024];
 	char line[1024], w1[1024], w2[1024];
 	FILE* fp = fopen(cfgName, "r");
 	FILE* fp = fopen(cfgName, "r");
@@ -2749,46 +2840,13 @@ bool char_config_read(const char* cfgName, bool normal){
 #else
 #else
 		} else if (strcmpi(w1, "start_point_pre") == 0) {
 		} else if (strcmpi(w1, "start_point_pre") == 0) {
 #endif
 #endif
-			char map[MAP_NAME_LENGTH_EXT];
-			short x, y;
-			if (sscanf(w2, "%15[^,],%6hd,%6hd", map, &x, &y) < 3){
-				ShowWarning( "Specified start_point has an invalid format.\n" );
-				continue;
-			}
-			charserv_config.start_point.map = mapindex_name2id(map);
-			if (!charserv_config.start_point.map)
-				ShowError("Specified start_point %s not found in map-index cache.\n", map);
-			charserv_config.start_point.x = x;
-			charserv_config.start_point.y = y;
+			char_config_split_startpoint(w2);
 		} else if (strcmpi(w1, "start_zeny") == 0) {
 		} else if (strcmpi(w1, "start_zeny") == 0) {
 			charserv_config.start_zeny = atoi(w2);
 			charserv_config.start_zeny = atoi(w2);
 			if (charserv_config.start_zeny < 0)
 			if (charserv_config.start_zeny < 0)
 				charserv_config.start_zeny = 0;
 				charserv_config.start_zeny = 0;
 		} else if (strcmpi(w1, "start_items") == 0) {
 		} else if (strcmpi(w1, "start_items") == 0) {
-			int i=0;
-			char *lineitem, **fields;
-			int fields_length = 3+1;
-			fields = (char**)aMalloc(fields_length*sizeof(char*));
-
-			lineitem = strtok(w2, ":");
-			while (lineitem != NULL) {
-				int n = sv_split(lineitem, strlen(lineitem), 0, ',', fields, fields_length, SV_NOESCAPE_NOTERMINATE);
-				if(n+1 < fields_length){
-					ShowDebug("start_items: not enough arguments for %s! Skipping...\n",lineitem);
-					lineitem = strtok(NULL, ":"); //next itemline
-					continue;
-				}
-				if(i > MAX_STARTITEM){
-					ShowDebug("start_items: too many items, only %d are allowed! Ignoring parameter %s...\n",MAX_STARTITEM,lineitem);
-				} else {
-					start_items[i].nameid = max(0,atoi(fields[1]));
-					start_items[i].amount = max(0,atoi(fields[2]));
-					start_items[i].pos = max(0,atoi(fields[3]));
-				}
-				lineitem = strtok(NULL, ":"); //next itemline
-				i++;
-			}
-			aFree(fields);
+			char_config_split_startitem(w2);
 		} else if(strcmpi(w1,"log_char")==0) {		//log char or not [devil]
 		} else if(strcmpi(w1,"log_char")==0) {		//log char or not [devil]
 			charserv_config.log_char = atoi(w2);
 			charserv_config.log_char = atoi(w2);
 		} else if (strcmpi(w1, "unknown_char_name") == 0) {
 		} else if (strcmpi(w1, "unknown_char_name") == 0) {
@@ -2870,7 +2928,6 @@ bool char_config_read(const char* cfgName, bool normal){
 	return true;
 	return true;
 }
 }
 
 
-
 /*
 /*
  * Message conf function
  * Message conf function
  */
  */

+ 6 - 1
src/char/char.h

@@ -15,6 +15,9 @@
 extern int login_fd; //login file descriptor
 extern int login_fd; //login file descriptor
 extern int char_fd; //char file descriptor
 extern int char_fd; //char file descriptor
 
 
+#define MAX_STARTPOINT 5
+#define MAX_STARTITEM 32
+
 enum E_CHARSERVER_ST {
 enum E_CHARSERVER_ST {
 	CHARSERVER_ST_RUNNING = CORE_ST_LAST,
 	CHARSERVER_ST_RUNNING = CORE_ST_LAST,
 	CHARSERVER_ST_STARTING,
 	CHARSERVER_ST_STARTING,
@@ -142,7 +145,9 @@ struct CharServ_Config {
 	int log_inter;	// loggin inter or not [devil]
 	int log_inter;	// loggin inter or not [devil]
 	int char_check_db;	///cheking sql-table at begining ?
 	int char_check_db;	///cheking sql-table at begining ?
 
 
-	struct point start_point; // Initial position the player will spawn on server
+	struct point start_point[MAX_STARTPOINT]; // Initial position the player will spawn on the server
+	short start_point_count; // Number of positions read
+	struct startitem start_items[MAX_STARTITEM]; // Initial items the player with spawn with on the server
 	int console;
 	int console;
 	int max_connect_user;
 	int max_connect_user;
 	int gm_allow_group;
 	int gm_allow_group;

+ 7 - 1
src/common/mapindex.h

@@ -4,6 +4,8 @@
 #ifndef _MAPINDEX_H_
 #ifndef _MAPINDEX_H_
 #define _MAPINDEX_H_
 #define _MAPINDEX_H_
 
 
+#include "../config/renewal.h"
+
 #define MAX_MAPINDEX 2000
 #define MAX_MAPINDEX 2000
 
 
 //Some definitions for the mayor city maps.
 //Some definitions for the mayor city maps.
@@ -31,7 +33,11 @@
 #define MAP_RACHEL "rachel"
 #define MAP_RACHEL "rachel"
 #define MAP_VEINS "veins"
 #define MAP_VEINS "veins"
 #define MAP_JAIL "sec_pri"
 #define MAP_JAIL "sec_pri"
-#define MAP_NOVICE "new_1-1"
+#ifdef RENEWAL
+	#define MAP_NOVICE "iz_int"
+#else
+	#define MAP_NOVICE "new_1-1"
+#endif
 #define MAP_MOSCOVIA "moscovia"
 #define MAP_MOSCOVIA "moscovia"
 #define MAP_MIDCAMP "mid_camp"
 #define MAP_MIDCAMP "mid_camp"
 #define MAP_MANUK "manuk"
 #define MAP_MANUK "manuk"

+ 5 - 0
src/common/mmo.h

@@ -219,6 +219,11 @@ struct point {
 	short x,y;
 	short x,y;
 };
 };
 
 
+struct startitem {
+	unsigned short nameid, amount;
+	short pos;
+};
+
 enum e_skill_flag
 enum e_skill_flag
 {
 {
 	SKILL_FLAG_PERMANENT,
 	SKILL_FLAG_PERMANENT,

+ 1 - 1
src/config/const.h

@@ -103,7 +103,7 @@
     #define MAP_DEFAULT_X 97
     #define MAP_DEFAULT_X 97
     #define MAP_DEFAULT_Y 90
     #define MAP_DEFAULT_Y 90
 #else
 #else
-    #define MAP_DEFAULT_NAME "new_zone01"
+    #define MAP_DEFAULT_NAME "new_1-1"
     #define MAP_DEFAULT_X 53
     #define MAP_DEFAULT_X 53
     #define MAP_DEFAULT_Y 111
     #define MAP_DEFAULT_Y 111
 #endif
 #endif

+ 4 - 0
src/map/atcommand.c

@@ -1874,7 +1874,11 @@ ACMD_FUNC(go)
 		{ MAP_UMBALA,       89, 157 }, // 12=Umbala
 		{ MAP_UMBALA,       89, 157 }, // 12=Umbala
 		{ MAP_NIFLHEIM,     21, 153 }, // 13=Niflheim
 		{ MAP_NIFLHEIM,     21, 153 }, // 13=Niflheim
 		{ MAP_LOUYANG,     217,  40 }, // 14=Louyang
 		{ MAP_LOUYANG,     217,  40 }, // 14=Louyang
+#ifdef RENEWAL
+		{ MAP_NOVICE,       97, 90  }, // 15=Training Grounds (Renewal)
+#else
 		{ MAP_NOVICE,       53, 111 }, // 15=Training Grounds
 		{ MAP_NOVICE,       53, 111 }, // 15=Training Grounds
+#endif
 		{ MAP_JAIL,         23,  61 }, // 16=Prison
 		{ MAP_JAIL,         23,  61 }, // 16=Prison
 		{ MAP_JAWAII,      249, 127 }, // 17=Jawaii
 		{ MAP_JAWAII,      249, 127 }, // 17=Jawaii
 		{ MAP_AYOTHAYA,    151, 117 }, // 18=Ayothaya
 		{ MAP_AYOTHAYA,    151, 117 }, // 18=Ayothaya