Rewrote Quest Log system.
git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@13959 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
parent
caadb5a546
commit
698e7a0fc0
@ -3,6 +3,8 @@ Date Added
|
||||
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
|
||||
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
|
||||
|
||||
09/07/25
|
||||
* Rewrote Quest Log system.
|
||||
09/07/21
|
||||
* Added proper bounds of INT_MIN to INT_MAX for hp/sp when being sent to/from status_damage/status_heal for negative values because of INT_MAX being (-INT_MIN - 1). [Paradox924X]
|
||||
09/07/17
|
||||
|
@ -120,8 +120,7 @@ pet_db: pet
|
||||
friend_db: friends
|
||||
mail_db: mail
|
||||
auction_db: auction
|
||||
quest_db: quest
|
||||
quest_obj_db: quest_objective
|
||||
quest_db: questlog
|
||||
|
||||
// Map Database Tables
|
||||
item_db_db: item_db
|
||||
|
@ -1781,3 +1781,7 @@ TW_TOWER 812
|
||||
4_M_MOCASS1 997
|
||||
4_M_MOCASS2 998
|
||||
4_M_MUT1 999
|
||||
|
||||
HAVEQUEST 0
|
||||
PLAYTIME 1
|
||||
HUNTING 2
|
||||
|
@ -1003,7 +1003,7 @@ packet_ver: 22
|
||||
0x02b3,107
|
||||
0x02b4,6
|
||||
0x02b5,-1
|
||||
0x02b6,7
|
||||
0x02b6,7,queststate,2:6
|
||||
0x02b7,7
|
||||
0x02b8,22
|
||||
0x02b9,191
|
||||
@ -1017,7 +1017,7 @@ packet_ver: 22
|
||||
0x02c4,26,partyinvite2,2
|
||||
0x02c5,30
|
||||
0x02c6,30
|
||||
0x02c7,7,replypartyinvite2,2,6
|
||||
0x02c7,7,replypartyinvite2,2:6
|
||||
0x02c8,3
|
||||
0x02c9,3
|
||||
0x02ca,3
|
||||
|
@ -130,6 +130,8 @@
|
||||
//= Extended the behaviour of duplicates (warps/shops/cashshops). [FlavioJS]
|
||||
//= 3.26.20090702
|
||||
//= Replaced 'bonusautoscript' by 'autobonus'. [Inkfish]
|
||||
//= 3.27.20090725
|
||||
//= Added Quest Log related commands. [Inkfish]
|
||||
//=========================================================
|
||||
|
||||
This document is a reference manual for all the scripting commands and functions
|
||||
@ -6527,5 +6529,57 @@ instance times out while inactive.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
========================
|
||||
|8.- Quest Log commands.|
|
||||
========================
|
||||
---------------------------------------
|
||||
|
||||
*setquest <ID>;
|
||||
|
||||
Place quest of <ID> in the users quest log, the state of which is "active".
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*completequest <ID>;
|
||||
|
||||
Change the state for the given quest <ID> to "complete" and remove from the users quest log.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*erasequest <ID>;
|
||||
|
||||
Remove the quest of the given <ID> from the user's quest log.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*changequest <ID>,<ID2>;
|
||||
|
||||
Remove quest of the given <ID> from the user's quest log, and change state to "complete".
|
||||
Add quest of the <ID2> to the the quest log, and the state is "active".
|
||||
|
||||
---------------------------------------
|
||||
|
||||
checkquest(<ID>{,PLAYTIME|HUNTING});
|
||||
|
||||
If no additonal argument supplied, return the state of the quest:
|
||||
-1 = Quest not started (not in quest log)
|
||||
0 = Quest has been given, but the state is "inactive"
|
||||
1 = Quest has been given, and the state is "active"
|
||||
2 = Quest comepleted
|
||||
|
||||
If parameter "PLAYTIME" is supplied:
|
||||
-1 = Quest not started (not in quest log)
|
||||
0 = the time limit has not yet been reached
|
||||
1 = the time limit has not been reached but the quest is marked as complete
|
||||
2 = the time limit has been reached
|
||||
|
||||
If parameter "HUNTING" is supplied:
|
||||
-1 = Quest not started (not in quest log)
|
||||
0 = you haven't killed all of the target monsters and the time limit has not been reached.
|
||||
1 = you haven't killed all of the target monsters but the time limit has been reached.
|
||||
2 = you've killed all of the target monsters
|
||||
|
||||
---------------------------------------
|
||||
|
||||
Whew.
|
||||
That's about all of them.
|
||||
|
@ -58,8 +58,7 @@ char mail_db[256] = "mail"; // MAIL SYSTEM
|
||||
char auction_db[256] = "auction"; // Auctions System
|
||||
char friend_db[256] = "friends";
|
||||
char hotkey_db[256] = "hotkey";
|
||||
char quest_db[256] = "quest";
|
||||
char quest_obj_db[256] = "quest_objective";
|
||||
char quest_db[256] = "questlog";
|
||||
|
||||
//If your code editor is having problems syntax highlighting this file, uncomment this and RECOMMENT IT BEFORE COMPILING
|
||||
//#undef TXT_SQL_CONVERT
|
||||
@ -3639,8 +3638,6 @@ void sql_config_read(const char* cfgName)
|
||||
strcpy(hotkey_db,w2);
|
||||
else if(!strcmpi(w1,"quest_db"))
|
||||
strcpy(quest_db,w2);
|
||||
else if(!strcmpi(w1,"quest_obj_db"))
|
||||
strcpy(quest_obj_db, w2);
|
||||
#ifndef TXT_SQL_CONVERT
|
||||
else if(!strcmpi(w1,"db_path"))
|
||||
strcpy(db_path,w2);
|
||||
|
@ -59,7 +59,6 @@ extern char pet_db[256];
|
||||
extern char mail_db[256];
|
||||
extern char auction_db[256];
|
||||
extern char quest_db[256];
|
||||
extern char quest_obj_db[256];
|
||||
|
||||
extern int db_use_sqldbs; // added for sql item_db read for char server [Valaris]
|
||||
|
||||
|
@ -20,10 +20,8 @@
|
||||
//Load entire questlog for a character
|
||||
int mapif_quests_fromsql(int char_id, struct quest questlog[])
|
||||
{
|
||||
|
||||
int count, i, j, num;
|
||||
int i;
|
||||
struct quest tmp_quest;
|
||||
struct quest_objective tmp_quest_objective;
|
||||
SqlStmt * stmt;
|
||||
|
||||
stmt = SqlStmt_Malloc(sql_handle);
|
||||
@ -34,42 +32,29 @@ int mapif_quests_fromsql(int char_id, struct quest questlog[])
|
||||
}
|
||||
|
||||
memset(&tmp_quest, 0, sizeof(struct quest));
|
||||
memset(&tmp_quest_objective, 0, sizeof(struct quest_objective));
|
||||
|
||||
if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST)
|
||||
if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `mob1`, `count1`, `mob2`, `count2`, `mob3`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST)
|
||||
|| SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|
||||
|| SQL_ERROR == SqlStmt_Execute(stmt)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) )
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT, &tmp_quest.mob[0], 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT, &tmp_quest.mob[1], 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_INT, &tmp_quest.mob[2], 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL) )
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
|
||||
for( i = 0; i < MAX_QUEST && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
|
||||
{
|
||||
memcpy(&questlog[i], &tmp_quest, sizeof(tmp_quest));
|
||||
questlog[i].num_objectives = (!questlog[i].mob[0] ? 0 : !questlog[i].mob[1] ? 1 : !questlog[i].mob[2] ? 2 : 3);
|
||||
}
|
||||
count = i;
|
||||
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
|
||||
if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `num`, `name`, `count` FROM `%s` WHERE `char_id`=? AND `quest_id`=? LIMIT %d", quest_obj_db, MAX_QUEST_OBJECTIVES)
|
||||
|| SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|
||||
|| SQL_ERROR == SqlStmt_BindParam(stmt, 1, SQLDT_INT, &questlog[i].quest_id, 0)
|
||||
|| SQL_ERROR == SqlStmt_Execute(stmt)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &num, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_STRING, &tmp_quest_objective.name, NAME_LENGTH, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_INT, &tmp_quest_objective.count, 0, NULL, NULL) )
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
|
||||
for( j = 0; j < MAX_QUEST && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++j )
|
||||
{
|
||||
memcpy(&questlog[i].objectives[num], &tmp_quest_objective, sizeof(struct quest_objective));
|
||||
}
|
||||
questlog[i].num_objectives = j;
|
||||
|
||||
}
|
||||
SqlStmt_Free(stmt);
|
||||
return count;
|
||||
return i;
|
||||
}
|
||||
|
||||
//Delete a quest
|
||||
@ -86,12 +71,6 @@ int mapif_parse_quest_delete(int fd)
|
||||
success = false;
|
||||
}
|
||||
|
||||
if ( success && SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_obj_db, quest_id, char_id) )
|
||||
{
|
||||
Sql_ShowDebug(sql_handle);
|
||||
success = false;
|
||||
}
|
||||
|
||||
WFIFOHEAD(fd,11);
|
||||
WFIFOW(fd,0) = 0x3862;
|
||||
WFIFOL(fd,2) = char_id;
|
||||
@ -111,13 +90,11 @@ int mapif_parse_quest_add(int fd)
|
||||
bool success = true;
|
||||
int char_id = RFIFOL(fd,4);
|
||||
struct quest qd;
|
||||
int i;
|
||||
|
||||
memcpy(&qd, RFIFOP(fd,8), RFIFOW(fd,2)-8);
|
||||
|
||||
StringBuf_Init(&buf);
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`) VALUES ('%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state);
|
||||
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `mob1`, `count1`, `mob2`, `count2`, `mob3`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.mob[0], qd.count[0], qd.mob[1], qd.count[1], qd.mob[2], qd.count[2]);
|
||||
|
||||
if ( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
|
||||
{
|
||||
@ -125,20 +102,6 @@ int mapif_parse_quest_add(int fd)
|
||||
success = false;
|
||||
}
|
||||
|
||||
for(i=0; i<qd.num_objectives && success; i++)
|
||||
{
|
||||
|
||||
StringBuf_Clear(&buf);
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s`(`quest_id`, `char_id`, `num`, `name`, `count`) VALUES ('%d', '%d', '%d', '%s', '%d')",
|
||||
quest_obj_db, qd.quest_id, char_id, i, qd.objectives[i].name, qd.objectives[i].count);
|
||||
|
||||
if ( success && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
|
||||
{
|
||||
Sql_ShowDebug(sql_handle);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
WFIFOHEAD(fd,11);
|
||||
WFIFOW(fd,0) = 0x3861;
|
||||
WFIFOL(fd,2) = char_id;
|
||||
@ -152,17 +115,48 @@ int mapif_parse_quest_add(int fd)
|
||||
|
||||
}
|
||||
|
||||
//Update a questlog
|
||||
int mapif_parse_quest_update(int fd)
|
||||
{
|
||||
|
||||
StringBuf buf;
|
||||
bool success = true;
|
||||
int char_id = RFIFOL(fd,4);
|
||||
struct quest qd;
|
||||
|
||||
memcpy(&qd, RFIFOP(fd,8), RFIFOW(fd,2)-8);
|
||||
|
||||
StringBuf_Init(&buf);
|
||||
StringBuf_Printf(&buf, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id);
|
||||
|
||||
if ( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
|
||||
{
|
||||
Sql_ShowDebug(sql_handle);
|
||||
success = false;
|
||||
}
|
||||
|
||||
WFIFOHEAD(fd,11);
|
||||
WFIFOW(fd,0) = 0x3863;
|
||||
WFIFOL(fd,2) = char_id;
|
||||
WFIFOL(fd,6) = qd.quest_id;
|
||||
WFIFOB(fd,10) = success?1:0;
|
||||
WFIFOSET(fd,11);
|
||||
|
||||
StringBuf_Destroy(&buf);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
//Send questlog to map server
|
||||
int mapif_send_quests(int fd, int char_id)
|
||||
{
|
||||
|
||||
struct quest tmp_questlog[MAX_QUEST];
|
||||
int num_quests, i;
|
||||
int num_quests, i, num_complete = 0;
|
||||
int complete[MAX_QUEST];
|
||||
|
||||
for(i=0; i<MAX_QUEST; i++)
|
||||
{
|
||||
memset(&tmp_questlog[i], 0, sizeof(struct quest));
|
||||
}
|
||||
memset(tmp_questlog, 0, sizeof(tmp_questlog));
|
||||
memset(complete, 0, sizeof(complete));
|
||||
|
||||
num_quests = mapif_quests_fromsql(char_id, tmp_questlog);
|
||||
|
||||
@ -171,11 +165,21 @@ int mapif_send_quests(int fd, int char_id)
|
||||
WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8;
|
||||
WFIFOL(fd,4) = char_id;
|
||||
|
||||
for(i=0; i<num_quests; i++)
|
||||
//Active and inactive quests
|
||||
for( i = 0; i < num_quests; i++ )
|
||||
{
|
||||
memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest));
|
||||
if( tmp_questlog[i].state == Q_COMPLETE )
|
||||
{
|
||||
complete[num_complete++] = i;
|
||||
continue;
|
||||
}
|
||||
memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest));
|
||||
}
|
||||
|
||||
// Completed quests
|
||||
for( i = num_quests - num_complete; i < num_quests; i++ )
|
||||
memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest));
|
||||
|
||||
WFIFOSET(fd,num_quests*sizeof(struct quest)+8);
|
||||
|
||||
return 0;
|
||||
@ -196,6 +200,7 @@ int inter_quest_parse_frommap(int fd)
|
||||
case 0x3060: mapif_parse_loadquestrequest(fd); break;
|
||||
case 0x3061: mapif_parse_quest_add(fd); break;
|
||||
case 0x3062: mapif_parse_quest_delete(fd); break;
|
||||
case 0x3063: mapif_parse_quest_update(fd); break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ int inter_recv_packet_length[] = {
|
||||
-1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030-
|
||||
5, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040-
|
||||
-1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus]
|
||||
6,-1,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin]
|
||||
6,-1,10,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish]
|
||||
-1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3070- Mercenary packets [Zephyrus]
|
||||
48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080-
|
||||
-1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator]
|
||||
|
@ -50,7 +50,7 @@
|
||||
#define MAX_GUILDCASTLE 34 // Updated to include new entries for WoE:SE. [L0ne_W0lf]
|
||||
#define MAX_GUILDLEVEL 50
|
||||
#define MAX_GUARDIANS 8 //Local max per castle. [Skotlex]
|
||||
#define MAX_QUEST 25 //Max quests for a PC
|
||||
#define MAX_QUEST_DB 500 //Max quests that the server will load
|
||||
#define MAX_QUEST_OBJECTIVES 3 //Max quest objectives for a quest
|
||||
|
||||
#define MIN_HAIR_STYLE battle_config.min_hair_style
|
||||
@ -126,24 +126,17 @@ enum item_types {
|
||||
};
|
||||
|
||||
|
||||
//Questlog system [Kevin]
|
||||
typedef enum quest_state { Q_INACTIVE, Q_ACTIVE } quest_state;
|
||||
|
||||
struct quest_objective {
|
||||
|
||||
char name[NAME_LENGTH];
|
||||
int count;
|
||||
|
||||
};
|
||||
//Questlog system [Kevin] [Inkfish]
|
||||
typedef enum quest_state { Q_INACTIVE, Q_ACTIVE, Q_COMPLETE } quest_state;
|
||||
|
||||
struct quest {
|
||||
|
||||
int quest_id;
|
||||
unsigned int time;
|
||||
int mob[MAX_QUEST_OBJECTIVES];
|
||||
int count[MAX_QUEST_OBJECTIVES];
|
||||
quest_state state;
|
||||
int num_objectives;
|
||||
int time;
|
||||
struct quest_objective objectives[MAX_QUEST_OBJECTIVES];
|
||||
|
||||
int num_objectives;
|
||||
};
|
||||
|
||||
struct item {
|
||||
|
@ -288,6 +288,8 @@ int chrif_save(struct map_session_data *sd, int flag)
|
||||
merc_save(sd->hd);
|
||||
if( sd->md && mercenary_get_lifetime(sd->md) > 0 )
|
||||
mercenary_save(sd->md);
|
||||
if( sd->num_quests )
|
||||
quest_save(sd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -8189,8 +8189,6 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
|
||||
mail_clear(sd);
|
||||
#endif
|
||||
|
||||
quest_pc_login(sd);
|
||||
|
||||
if(map[sd->bl.m].flag.loadevent) // Lance
|
||||
npc_script_event(sd, NPCE_LOADMAP);
|
||||
|
||||
@ -12548,39 +12546,28 @@ void clif_parse_EquipTick(int fd, struct map_session_data* sd)
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Questlog System [Kevin]
|
||||
* 02B5 <packet_len>.W <ignored>.L { }.10B* <-- UNKOWN PACKET
|
||||
* 02B6 <quest_id>.L <state>.B
|
||||
* Questlog System [Kevin] [Inkfish]
|
||||
*------------------------------------------*/
|
||||
|
||||
void clif_parse_questStateAck(int fd, struct map_session_data * sd)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//Send simple list of quests upon login
|
||||
//* 02B1 <packet_len>.W <ignored>.L { <quest_id>.L <state>.B }.5B*
|
||||
void clif_send_questlog(struct map_session_data * sd)
|
||||
{
|
||||
int fd = sd->fd;
|
||||
int i;
|
||||
int len = sd->avail_quests*5+8;
|
||||
|
||||
WFIFOHEAD(fd,sd->num_quests*5+8);
|
||||
WFIFOHEAD(fd,len);
|
||||
WFIFOW(fd, 0) = 0x02B1;
|
||||
WFIFOW(fd, 2) = sd->num_quests*5+8;
|
||||
WFIFOW(fd, 2) = len;
|
||||
WFIFOL(fd, 4) = sd->avail_quests;
|
||||
|
||||
for(i=0; i<MAX_QUEST; i++)
|
||||
for( i = 0; i < sd->avail_quests; i++ )
|
||||
{
|
||||
if(!sd->quest_log[i].quest_id)
|
||||
continue;
|
||||
|
||||
|
||||
WFIFOL(fd, i*5+8) = sd->quest_log[i].quest_id;
|
||||
WFIFOB(fd, i*5+12) = sd->quest_log[i].state;
|
||||
|
||||
}
|
||||
|
||||
WFIFOSET(fd, WFIFOW(fd, 2));
|
||||
WFIFOSET(fd, len);
|
||||
|
||||
}
|
||||
|
||||
@ -12590,31 +12577,29 @@ void clif_send_questlog_info(struct map_session_data * sd)
|
||||
{
|
||||
int fd = sd->fd;
|
||||
int i, j;
|
||||
int len = sd->avail_quests*104+8;
|
||||
struct mob_db *mob;
|
||||
|
||||
WFIFOHEAD(fd,sd->num_quests*104+8);
|
||||
WFIFOHEAD(fd, len);
|
||||
WFIFOW(fd, 0) = 0x02B2;
|
||||
WFIFOW(fd, 2) = sd->num_quests*104+8;
|
||||
WFIFOW(fd, 2) = len;
|
||||
WFIFOL(fd, 4) = sd->avail_quests;
|
||||
|
||||
for(i=0; i<MAX_QUEST; i++)
|
||||
for( i = 0; i < sd->avail_quests; i++ )
|
||||
{
|
||||
if(!sd->quest_log[i].quest_id)
|
||||
continue;
|
||||
|
||||
WFIFOL(fd, i*104+8) = sd->quest_log[i].quest_id;
|
||||
|
||||
// I have no idea what the time field does [Kevin]
|
||||
WFIFOL(fd, i*104+16) = 0;
|
||||
WFIFOL(fd, i*104+16) = sd->quest_log[i].time;
|
||||
WFIFOW(fd, i*104+20) = sd->quest_log[i].num_objectives;
|
||||
|
||||
for(j=0; j<sd->quest_log[i].num_objectives; j++)
|
||||
for( j = 0 ; j < sd->quest_log[i].num_objectives; j++ )
|
||||
{
|
||||
WFIFOW(fd, i*104+26+j*30) = sd->quest_log[i].objectives[j].count;
|
||||
memcpy(WFIFOP(fd, i*104+28+j*30), sd->quest_log[i].objectives[j].name, NAME_LENGTH);
|
||||
WFIFOW(fd, i*104+26+j*30) = sd->quest_log[i].count[j];
|
||||
mob = mob_db(sd->quest_log[i].mob[j]);
|
||||
memcpy(WFIFOP(fd, i*104+28+j*30), mob?mob->jname:"NULL", NAME_LENGTH);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WFIFOSET(fd, WFIFOW(fd, 2));
|
||||
WFIFOSET(fd, len);
|
||||
}
|
||||
|
||||
//Send info when objective info needs an update
|
||||
@ -12623,23 +12608,24 @@ void clif_send_quest_info(struct map_session_data * sd, struct quest * qd)
|
||||
{
|
||||
int fd = sd->fd;
|
||||
int i;
|
||||
//int len = MAX_QUEST_OBJECTIVES*30+17;
|
||||
struct mob_db *mob;
|
||||
|
||||
WFIFOHEAD(fd,qd->num_objectives*30+17);
|
||||
WFIFOHEAD(fd, packet_len(0x02B3));
|
||||
WFIFOW(fd, 0) = 0x02B3;
|
||||
WFIFOL(fd, 2) = qd->quest_id;
|
||||
WFIFOB(fd, 6) = qd->state;
|
||||
|
||||
//Same time value thing
|
||||
WFIFOW(fd, 11) = 0;
|
||||
WFIFOL(fd, 11) = qd->time;
|
||||
WFIFOW(fd, 15) = qd->num_objectives;
|
||||
|
||||
for(i=0; i<qd->num_objectives; i++)
|
||||
for( i = 0; i < qd->num_objectives; i++ )
|
||||
{
|
||||
WFIFOW(fd, i*30+21) = qd->objectives[i].count;
|
||||
memcpy(WFIFOP(fd, i*30+23), qd->objectives[i].name, NAME_LENGTH);
|
||||
WFIFOW(fd, i*30+21) = qd->count[i];
|
||||
mob = mob_db(qd->mob[i]);
|
||||
memcpy(WFIFOP(fd, i*30+23), mob?mob->jname:"NULL", NAME_LENGTH);
|
||||
}
|
||||
|
||||
WFIFOSET(fd, qd->num_objectives*30+17);
|
||||
WFIFOSET(fd, packet_len(0x02B3));
|
||||
}
|
||||
|
||||
//Send delete msg
|
||||
@ -12648,11 +12634,18 @@ void clif_send_quest_delete(struct map_session_data * sd, int quest_id)
|
||||
{
|
||||
int fd = sd->fd;
|
||||
|
||||
WFIFOHEAD(fd, 6);
|
||||
WFIFOHEAD(fd, packet_len(0x02B4));
|
||||
WFIFOW(fd, 0) = 0x02B4;
|
||||
WFIFOL(fd, 2) = quest_id;
|
||||
WFIFOSET(fd, 6);
|
||||
WFIFOSET(fd, packet_len(0x02B4));
|
||||
}
|
||||
|
||||
// * 02B5 <packet_len>.W <ignored>.L { }.10B* <-- UNKOWN PACKET
|
||||
|
||||
// * 02B6 <quest_id>.L <state>.B
|
||||
void clif_parse_questStateAck(int fd, struct map_session_data * sd)
|
||||
{
|
||||
quest_update_status(sd, RFIFOL(fd,2), RFIFOB(fd,6)?Q_ACTIVE:Q_INACTIVE);
|
||||
}
|
||||
|
||||
//Change active state of the quest
|
||||
@ -12661,11 +12654,11 @@ void clif_send_quest_status(struct map_session_data * sd, int quest_id, bool act
|
||||
{
|
||||
int fd = sd->fd;
|
||||
|
||||
WFIFOHEAD(fd, 7);
|
||||
WFIFOHEAD(fd, packet_len(0x02B7));
|
||||
WFIFOW(fd, 0) = 0x02B7;
|
||||
WFIFOL(fd, 2) = quest_id;
|
||||
WFIFOB(fd, 6) = active?1:0;
|
||||
WFIFOSET(fd, 7);
|
||||
WFIFOB(fd, 6) = active;
|
||||
WFIFOSET(fd, packet_len(0x02B7));
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
@ -13416,7 +13409,7 @@ static int packetdb_readdb(void)
|
||||
0, 0, 0, 6, 0, 0, 0, 0, 0, 8, 18, 0, 0, 0, 0, 0,
|
||||
0, 4, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,191, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0,117, 6, 0, 7, 7, 0,191, 0, 0, 0, 0, 0, 0,
|
||||
//#0x02C0
|
||||
0, 0, 0, 0, 0, 30, 0, 0, 0, 3, 0, 65, 4, 71, 10, 0,
|
||||
0, 0, 0, 0, 0, 0, 6, -1, 10, 10, 3, 0, -1, 32, 6, 0,
|
||||
@ -13632,6 +13625,8 @@ static int packetdb_readdb(void)
|
||||
{clif_parse_Auction_cancel,"auctioncancel"},
|
||||
{clif_parse_Auction_close,"auctionclose"},
|
||||
{clif_parse_Auction_bid,"auctionbid"},
|
||||
// Quest Log System
|
||||
{clif_parse_questStateAck,"queststate"},
|
||||
#endif
|
||||
{clif_parse_cashshop_buy,"cashshopbuy"},
|
||||
{clif_parse_ViewPlayerEquip,"viewplayerequip"},
|
||||
|
@ -431,14 +431,13 @@ void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* ts
|
||||
void clif_viewequip_fail(struct map_session_data* sd);
|
||||
void clif_equipcheckbox(struct map_session_data* sd);
|
||||
|
||||
//quest system [Kevin]
|
||||
//quest system [Kevin] [Inkfish]
|
||||
void clif_send_questlog(struct map_session_data * sd);
|
||||
void clif_send_questlog_info(struct map_session_data * sd);
|
||||
void clif_send_quest_info(struct map_session_data * sd, struct quest * qd);
|
||||
void clif_send_quest_delete(struct map_session_data * sd, int quest_id);
|
||||
void clif_send_quest_status(struct map_session_data * sd, int quest_id, bool active);
|
||||
|
||||
|
||||
int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target type);
|
||||
int do_final_clif(void);
|
||||
int do_init_clif(void);
|
||||
|
@ -38,7 +38,7 @@ static const int packet_len_table[]={
|
||||
10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830
|
||||
9, 9,-1,14, 0, 0, 0, 0, -1,74,-1,11, 11,-1, 0, 0, //0x3840
|
||||
-1,-1, 7, 7, 7,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3850 Auctions [Zephyrus]
|
||||
-1,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3860 Quests [Kevin]
|
||||
-1,11,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3860 Quests [Kevin] [Inkfish]
|
||||
-1, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3870 Mercenaries [Zephyrus]
|
||||
11,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3880
|
||||
-1,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3890 Homunculus [albator]
|
||||
@ -1340,21 +1340,26 @@ int intif_request_questlog(TBL_PC *sd)
|
||||
|
||||
int intif_parse_questlog(int fd)
|
||||
{
|
||||
|
||||
int num_quests = (RFIFOB(fd, 2)-8)/sizeof(struct quest);
|
||||
int char_id = RFIFOL(fd, 4);
|
||||
int i;
|
||||
TBL_PC * sd = map_charid2sd(char_id);
|
||||
|
||||
//User not online anymore
|
||||
if(!sd)
|
||||
return 0;
|
||||
return -1;
|
||||
|
||||
for(i=0; i<num_quests; i++)
|
||||
sd->avail_quests = sd->num_quests = (RFIFOB(fd, 2)-8)/sizeof(struct quest);
|
||||
|
||||
memset(&sd->quest_log, 0, sizeof(sd->quest_log));
|
||||
|
||||
for( i = 0; i < sd->num_quests; i++ )
|
||||
{
|
||||
memcpy(&sd->quest_log[i], RFIFOP(fd, i*sizeof(struct quest)+8), sizeof(struct quest));
|
||||
if( sd->quest_log[i].state == Q_COMPLETE )
|
||||
sd->avail_quests--;
|
||||
}
|
||||
sd->num_quests = num_quests;
|
||||
|
||||
quest_pc_login(sd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1401,6 +1406,27 @@ int intif_quest_add(int char_id, struct quest * qd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intif_quest_save(int char_id, struct quest * qd)
|
||||
{
|
||||
if(CheckForCharServer())
|
||||
return 0;
|
||||
|
||||
WFIFOHEAD(inter_fd, sizeof(struct quest) + 8);
|
||||
WFIFOW(inter_fd,0) = 0x3063;
|
||||
WFIFOW(inter_fd,2) = sizeof(struct quest) + 8;
|
||||
WFIFOL(inter_fd,4) = char_id;
|
||||
memcpy(WFIFOP(inter_fd,8), qd, sizeof(struct quest));
|
||||
WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intif_parse_questSave(int fd)
|
||||
{
|
||||
quest_save_ack(RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOB(fd, 10));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef TXT_ONLY
|
||||
|
||||
/*==========================================
|
||||
@ -2038,6 +2064,7 @@ int intif_parse(int fd)
|
||||
case 0x3860: intif_parse_questlog(fd); break;
|
||||
case 0x3861: intif_parse_questAdd(fd); break;
|
||||
case 0x3862: intif_parse_questDelete(fd); break;
|
||||
case 0x3863: intif_parse_questSave(fd); break;
|
||||
|
||||
#ifndef TXT_ONLY
|
||||
// Mail System
|
||||
|
@ -77,6 +77,7 @@ int intif_homunculus_requestdelete(int homun_id);
|
||||
int intif_request_questlog(struct map_session_data * sd);
|
||||
int intif_quest_delete(int char_id, int quest_id);
|
||||
int intif_quest_add(int char_id, struct quest * qd);
|
||||
int intif_quest_save(int char_id, struct quest * qd);
|
||||
|
||||
// MERCENARY SYSTEM
|
||||
int intif_mercenary_create(struct s_mercenary *merc);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "unit.h"
|
||||
#include "battle.h"
|
||||
#include "battleground.h"
|
||||
#include "quest.h"
|
||||
#include "script.h"
|
||||
#include "mapreg.h"
|
||||
#include "guild.h"
|
||||
@ -4081,6 +4082,7 @@ int do_init(int argc, char *argv[])
|
||||
do_init_pet();
|
||||
do_init_merc();
|
||||
do_init_mercenary();
|
||||
do_init_quest();
|
||||
do_init_npc();
|
||||
do_init_unit();
|
||||
do_init_battleground();
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include "script.h"
|
||||
#include "atcommand.h"
|
||||
#include "date.h"
|
||||
#include "quest.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -1992,6 +1994,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
||||
}
|
||||
pc_setglobalreg(sd,"TK_MISSION_COUNT", sd->mission_count);
|
||||
}
|
||||
if( sd->avail_quests )
|
||||
quest_update_objective(sd, md->class_);
|
||||
}
|
||||
|
||||
// filter out entries not eligible for exp distribution
|
||||
|
@ -377,9 +377,11 @@ struct map_session_data {
|
||||
bool changed; // if true, should sync with charserver on next mailbox request
|
||||
} mail;
|
||||
|
||||
//Quest log system [Kevin]
|
||||
//Quest log system [Kevin] [Inkfish]
|
||||
int num_quests;
|
||||
struct quest quest_log[MAX_QUEST];
|
||||
int avail_quests;
|
||||
bool save_quest[MAX_QUEST_DB];
|
||||
struct quest quest_log[MAX_QUEST_DB];
|
||||
|
||||
// temporary debug [flaviojs]
|
||||
const char* debug_file;
|
||||
|
321
src/map/quest.c
321
src/map/quest.c
@ -33,46 +33,61 @@
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#define MAX_QUEST 25
|
||||
|
||||
//Send quest info on login
|
||||
int quest_pc_login(TBL_PC * sd)
|
||||
{
|
||||
|
||||
if(sd->num_quests == 0)
|
||||
return 1;
|
||||
|
||||
clif_send_questlog(sd);
|
||||
clif_send_questlog_info(sd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int quest_add(TBL_PC * sd, struct quest * qd)
|
||||
int quest_add(TBL_PC * sd, int quest_id)
|
||||
{
|
||||
|
||||
int i;
|
||||
int i, j, count;
|
||||
|
||||
//Search to see if this quest exists
|
||||
ARR_FIND(0, MAX_QUEST, i, sd->quest_log[i].quest_id == qd->quest_id);
|
||||
|
||||
//Already have this quest
|
||||
if(i!=MAX_QUEST)
|
||||
return 1;
|
||||
|
||||
//Find empty quest log spot
|
||||
ARR_FIND(0, MAX_QUEST, i, sd->quest_log[i].quest_id == 0);
|
||||
|
||||
//Quest log is full
|
||||
if(i == MAX_QUEST)
|
||||
if( quest_check_quest(sd, quest_id, HAVEQUEST) >= 0 )
|
||||
{
|
||||
ShowError("quest_add: you already have quest %d.\n",quest_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( (j = quest_search_db(quest_id)) < 0 )
|
||||
{
|
||||
ShowError("quest_add: quest %d not found in DB.\n",quest_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( sd->num_quests >= MAX_QUEST_DB || sd->avail_quests >= MAX_QUEST )
|
||||
{
|
||||
ShowError("quest_add: your quest log is full.(max quests: %d, max incompleted quests: %d)\n", MAX_QUEST_DB, MAX_QUEST);
|
||||
return 1;
|
||||
}
|
||||
|
||||
i = sd->avail_quests;
|
||||
memmove(&sd->quest_log[i+1], &sd->quest_log[i], sizeof(struct quest)*(sd->num_quests-sd->avail_quests));
|
||||
memset(&sd->quest_log[i], 0, sizeof(struct quest));
|
||||
sd->quest_log[i].quest_id = quest_db[j].id;
|
||||
if( quest_db[j].time )
|
||||
sd->quest_log[i].time = (unsigned int)(time(NULL) + quest_db[j].time);
|
||||
sd->quest_log[i].state = Q_ACTIVE;
|
||||
for( count = 0; count < MAX_QUEST_OBJECTIVES && quest_db[j].mob[count]; count++ )
|
||||
sd->quest_log[i].mob[count] = quest_db[j].mob[count];
|
||||
sd->quest_log[i].num_objectives = count;
|
||||
|
||||
//Copy over quest data
|
||||
memcpy(&sd->quest_log[i], qd, sizeof(struct quest));
|
||||
sd->num_quests++;
|
||||
sd->avail_quests++;
|
||||
|
||||
//Notify inter server
|
||||
intif_quest_add(sd->status.char_id, qd);
|
||||
intif_quest_add(sd->status.char_id, &sd->quest_log[i]);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int quest_add_ack(int char_id, int quest_id, int success)
|
||||
@ -83,26 +98,21 @@ int quest_add_ack(int char_id, int quest_id, int success)
|
||||
///Player no longer on map
|
||||
if(!sd)
|
||||
return -1;
|
||||
|
||||
ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == quest_id);
|
||||
if( i == sd->avail_quests )
|
||||
return -1; //Shouldn't happen!
|
||||
|
||||
//Search for quest
|
||||
ARR_FIND(0, MAX_QUEST, i, sd->quest_log[i].quest_id == quest_id);
|
||||
|
||||
//Quest not found, shouldn't happen?
|
||||
if(i == MAX_QUEST)
|
||||
return -1;
|
||||
|
||||
if(success)
|
||||
{
|
||||
//Notify client
|
||||
clif_send_quest_info(sd, &sd->quest_log[i]);
|
||||
}
|
||||
if( success )
|
||||
clif_send_quest_info(sd, &sd->quest_log[i]); //Notify client
|
||||
else
|
||||
{
|
||||
sd->avail_quests--;
|
||||
if( sd->num_quests < MAX_QUEST_DB && sd->quest_log[i+1].quest_id )
|
||||
memmove(&sd->quest_log[i], &sd->quest_log[i+1], sizeof(struct quest)*(sd->num_quests-i));
|
||||
memset(&sd->quest_log[--sd->num_quests], 0, sizeof(struct quest));
|
||||
ShowError("Quest %d for character %d could not be added!\n", quest_id, char_id);
|
||||
|
||||
//Zero quest
|
||||
memset(&sd->quest_log[i], 0, sizeof(struct quest));
|
||||
sd->num_quests--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -110,23 +120,117 @@ int quest_add_ack(int char_id, int quest_id, int success)
|
||||
|
||||
int quest_delete(TBL_PC * sd, int quest_id)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
//Search for quest
|
||||
ARR_FIND(0, MAX_QUEST, i, sd->quest_log[i].quest_id == quest_id);
|
||||
|
||||
//Quest not found
|
||||
if(i == MAX_QUEST)
|
||||
if( quest_check_quest(sd, quest_id, HAVEQUEST) < 0 ) //Quest not found
|
||||
{
|
||||
ShowError("quest_delete: quest %d not found in your quest log.\n",quest_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intif_quest_delete(sd->status.char_id, quest_id);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int quest_delete_ack(int char_id, int quest_id, int success)
|
||||
{
|
||||
int i;
|
||||
TBL_PC * sd = map_charid2sd(char_id);
|
||||
|
||||
///Player no longer on map
|
||||
if(!sd)
|
||||
return -1;
|
||||
|
||||
//Search for quest
|
||||
ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id);
|
||||
if(i == sd->num_quests) //Shouldn't happen!
|
||||
return -1;
|
||||
|
||||
if(success)
|
||||
{
|
||||
if( sd->quest_log[i].state != Q_COMPLETE )
|
||||
sd->avail_quests--;
|
||||
if( sd->num_quests < MAX_QUEST_DB && sd->quest_log[i+1].quest_id )
|
||||
memmove(&sd->quest_log[i], &sd->quest_log[i+1], sizeof(struct quest)*(sd->num_quests-i));
|
||||
memset(&sd->quest_log[--sd->num_quests], 0, sizeof(struct quest));
|
||||
clif_send_quest_delete(sd, quest_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError("Quest %d for character %d could not be deleted!\n", quest_id, char_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void quest_update_objective(TBL_PC * sd, int mob)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
for( i = 0; i < sd->avail_quests; i++ )
|
||||
{
|
||||
if( sd->quest_log[i].state != Q_ACTIVE )
|
||||
continue;
|
||||
|
||||
for( j = 0; j < MAX_QUEST_OBJECTIVES; j++ )
|
||||
if( sd->quest_log[i].mob[j] == mob )
|
||||
{
|
||||
sd->quest_log[i].count[j]++;
|
||||
sd->save_quest[i] = true;
|
||||
//clif_send_quest_info(sd, &sd->quest_log[i]); //TODO: Figure out the real packet [Inkfish]
|
||||
//break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int quest_update_status(TBL_PC * sd, int quest_id, int status)
|
||||
{
|
||||
int i;
|
||||
|
||||
//Search for quest
|
||||
ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == quest_id); // Only status of active and inactive quests can't be updated and completed quests can't [Inkfish]
|
||||
if(i == sd->avail_quests) //Quest not found
|
||||
{
|
||||
ShowError("Quest %d not found in your quest log!\n", quest_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sd->quest_log[i].state = (quest_state)status;
|
||||
if( status != Q_COMPLETE )
|
||||
{
|
||||
clif_send_quest_status(sd, quest_id, (bool)status);
|
||||
sd->save_quest[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct quest tmp_quest;
|
||||
|
||||
clif_send_quest_delete(sd, quest_id);
|
||||
sd->avail_quests--;
|
||||
|
||||
memcpy(&tmp_quest, &sd->quest_log[i],sizeof(struct quest));
|
||||
memcpy(&sd->quest_log[i], &sd->quest_log[sd->avail_quests],sizeof(struct quest));
|
||||
memcpy(&sd->quest_log[sd->avail_quests], &tmp_quest,sizeof(struct quest));
|
||||
|
||||
sd->save_quest[sd->avail_quests] = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int quest_save(TBL_PC * sd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < sd->num_quests; i++ )
|
||||
if( sd->save_quest[i] )
|
||||
intif_quest_save(sd->status.char_id, &sd->quest_log[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int quest_save_ack(int char_id, int quest_id, int success)
|
||||
{
|
||||
|
||||
int i;
|
||||
@ -137,65 +241,130 @@ int quest_delete_ack(int char_id, int quest_id, int success)
|
||||
return -1;
|
||||
|
||||
//Search for quest
|
||||
ARR_FIND(0, MAX_QUEST, i, sd->quest_log[i].quest_id == quest_id);
|
||||
|
||||
//Quest not found
|
||||
if(i == MAX_QUEST)
|
||||
ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id);
|
||||
if(i == sd->num_quests) //Quest not found
|
||||
return -1;
|
||||
|
||||
if(success)
|
||||
{
|
||||
|
||||
//Zero quest
|
||||
memset(&sd->quest_log[i], 0, sizeof(struct quest));
|
||||
sd->num_quests--;
|
||||
|
||||
//Notify client
|
||||
clif_send_quest_delete(sd, quest_id);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
sd->save_quest[i] = false;
|
||||
else
|
||||
ShowError("Quest %d for character %d could not be deleted!\n", quest_id, char_id);
|
||||
{
|
||||
ShowError("Quest %d for character %d could not be saved!\n", quest_id, char_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int quest_update_objective(TBL_PC * sd, int quest_id, int objective_num, const char * name, int count)
|
||||
int quest_check_quest(TBL_PC * sd, int quest_id, quest_check_type type)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
//Search for quest
|
||||
ARR_FIND(0, MAX_QUEST, i, sd->quest_log[i].quest_id == quest_id);
|
||||
|
||||
//Quest not found
|
||||
if(i == MAX_QUEST)
|
||||
ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id);
|
||||
if(i == sd->num_quests)
|
||||
return -1;
|
||||
|
||||
memcpy(&sd->quest_log[i].objectives[objective_num].name, name, NAME_LENGTH);
|
||||
sd->quest_log[i].objectives[objective_num].count = count;
|
||||
switch( type )
|
||||
{
|
||||
case HAVEQUEST:
|
||||
return sd->quest_log[i].state;
|
||||
case PLAYTIME:
|
||||
return (sd->quest_log[i].time < (unsigned int)time(NULL) ? 2 : sd->quest_log[i].state == Q_COMPLETE ? 1 : 0);
|
||||
case HUNTING:
|
||||
{
|
||||
int j = quest_search_db(quest_id);
|
||||
|
||||
//Notify client
|
||||
clif_send_quest_info(sd, &sd->quest_log[i]);
|
||||
if( j < 0 )
|
||||
{
|
||||
ShowError("quest_check_quest: quest not found in DB\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if( sd->quest_log[i].count[0] < quest_db[j].count[0] || sd->quest_log[i].count[1] < quest_db[j].count[1] || sd->quest_log[i].count[2] < quest_db[j].count[2] )
|
||||
{
|
||||
if( sd->quest_log[i].time < (unsigned int)time(NULL) )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
default:
|
||||
ShowError("quest_check_quest: Unknown parameter %d",type);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool quest_has_quest(TBL_PC * sd, int quest_id)
|
||||
int quest_search_db(int quest_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
ARR_FIND(0, MAX_QUEST, i, sd->quest_log[i].quest_id == quest_id);
|
||||
ARR_FIND(0, MAX_QUEST_DB,i,quest_id == quest_db[i].id);
|
||||
if( i == MAX_QUEST_DB )
|
||||
return -1;
|
||||
|
||||
return (i != MAX_QUEST);
|
||||
return i;
|
||||
}
|
||||
|
||||
int quest_update_status(TBL_PC * sd, int quest_id, bool status)
|
||||
int quest_read_db(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[1024];
|
||||
int j,k = 0;
|
||||
char *str[20],*p,*np;
|
||||
|
||||
sprintf(line, "%s/quest_db.txt", db_path);
|
||||
if( (fp=fopen(line,"r"))==NULL ){
|
||||
ShowError("can't read %s\n", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(fgets(line, sizeof(line), fp))
|
||||
{
|
||||
if(line[0]=='/' && line[1]=='/')
|
||||
continue;
|
||||
memset(str,0,sizeof(str));
|
||||
|
||||
for( j = 0, p = line; j < 8;j++ )
|
||||
{
|
||||
if((np=strchr(p,','))!=NULL)
|
||||
{
|
||||
str[j] = p;
|
||||
*np = 0;
|
||||
p = np + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError("quest_read_db: insufficient columes in line %s\n", line);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(str[0]==NULL)
|
||||
continue;
|
||||
|
||||
memset(&quest_db[k], 0, sizeof(quest_db[0]));
|
||||
|
||||
quest_db[k].id = atoi(str[0]);
|
||||
quest_db[k].time = atoi(str[1]);
|
||||
quest_db[k].mob[0] = atoi(str[2]);
|
||||
quest_db[k].count[0] = atoi(str[3]);
|
||||
quest_db[k].mob[1] = atoi(str[4]);
|
||||
quest_db[k].count[1] = atoi(str[5]);
|
||||
quest_db[k].mob[2] = atoi(str[6]);
|
||||
quest_db[k].count[2] = atoi(str[7]);
|
||||
//memcpy(quest_db[k].name, str[8], sizeof(str[8]));
|
||||
k++;
|
||||
}
|
||||
fclose(fp);
|
||||
ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","quest_db.txt");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void do_init_quest(void)
|
||||
{
|
||||
quest_read_db();
|
||||
}
|
||||
|
@ -4,19 +4,34 @@
|
||||
#ifndef _QUEST_H_
|
||||
#define _QUEST_H_
|
||||
|
||||
int quest_pc_login(TBL_PC * sd);
|
||||
int quest_load_info(TBL_PC * sd, struct mmo_charstatus * st);
|
||||
int quest_make_savedata(TBL_PC * sd);
|
||||
typedef enum quest_check_type { HAVEQUEST, PLAYTIME, HUNTING } quest_check_type;
|
||||
|
||||
int quest_add(TBL_PC * sd, struct quest * qd);
|
||||
struct s_quest_db {
|
||||
int id;
|
||||
unsigned int time;
|
||||
int mob[MAX_QUEST_OBJECTIVES];
|
||||
int count[MAX_QUEST_OBJECTIVES];
|
||||
//char name[NAME_LENGTH];
|
||||
};
|
||||
struct s_quest_db quest_db[MAX_QUEST_DB];
|
||||
|
||||
int quest_pc_login(TBL_PC * sd);
|
||||
|
||||
int quest_add(TBL_PC * sd, int quest_id);
|
||||
int quest_add_ack(int char_id, int quest_id, int success);
|
||||
|
||||
int quest_delete(TBL_PC * sd, int quest_id);
|
||||
int quest_delete_ack(int char_id, int quest_id, int success);
|
||||
|
||||
int quest_update_objective(TBL_PC * sd, int quest_id, int objective_num, const char * name, int count);
|
||||
int quest_update_status(TBL_PC * sd, int quest_id, bool status);
|
||||
void quest_update_objective(TBL_PC * sd, int mob);
|
||||
int quest_update_status(TBL_PC * sd, int quest_id, int status);
|
||||
int quest_save(TBL_PC * sd);
|
||||
int quest_save_ack(int char_id, int quest_id, int success);
|
||||
|
||||
bool quest_has_quest(TBL_PC * sd, int quest_id);
|
||||
int quest_check_quest(TBL_PC * sd, int quest_id, quest_check_type type);
|
||||
|
||||
int quest_search_db(int quest_id);
|
||||
|
||||
void do_init_quest();
|
||||
|
||||
#endif
|
||||
|
105
src/map/script.c
105
src/map/script.c
@ -13426,81 +13426,53 @@ BUILDIN_FUNC(readbook)
|
||||
Questlog script commands
|
||||
*******************/
|
||||
|
||||
BUILDIN_FUNC(getquest)
|
||||
BUILDIN_FUNC(setquest)
|
||||
{
|
||||
|
||||
TBL_PC * sd = script_rid2sd(st);
|
||||
struct quest qd;
|
||||
int i, count = 0;
|
||||
char * temp;
|
||||
|
||||
memset(&qd, 0, sizeof(struct quest));
|
||||
quest_add(sd, script_getnum(st, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
qd.quest_id = script_getnum(st, 2);
|
||||
qd.time = script_getnum(st, 3);
|
||||
qd.state = Q_ACTIVE;
|
||||
|
||||
for(i=0; i<(script_lastdata(st)-3) && (i/2) < MAX_QUEST_OBJECTIVES; i+=2)
|
||||
BUILDIN_FUNC(erasequest)
|
||||
{
|
||||
TBL_PC * sd = script_rid2sd(st);
|
||||
|
||||
quest_delete(sd, script_getnum(st, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUILDIN_FUNC(completequest)
|
||||
{
|
||||
TBL_PC * sd = script_rid2sd(st);
|
||||
|
||||
quest_update_status(sd, script_getnum(st, 2), Q_COMPLETE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUILDIN_FUNC(changequest)
|
||||
{
|
||||
TBL_PC * sd = script_rid2sd(st);
|
||||
int q1 = script_getnum(st, 2), q2 = script_getnum(st, 3);
|
||||
|
||||
if( quest_check_quest(sd, q1, HAVEQUEST) == Q_ACTIVE && quest_add(sd, q2) >= 0 )
|
||||
{
|
||||
temp = (char*)script_getstr(st, i+4);
|
||||
memcpy(&qd.objectives[i/2].name, temp, NAME_LENGTH);
|
||||
temp = NULL;
|
||||
qd.objectives[i/2].count = script_getnum(st, i+5);
|
||||
count++;
|
||||
quest_update_status(sd, q1, Q_COMPLETE);
|
||||
intif_quest_save(sd->status.char_id, &sd->quest_log[sd->avail_quests]);
|
||||
}
|
||||
|
||||
qd.num_objectives = count;
|
||||
|
||||
quest_add(sd, &qd);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
BUILDIN_FUNC(deletequest)
|
||||
{
|
||||
|
||||
TBL_PC * sd = script_rid2sd(st);
|
||||
int qid = script_getnum(st, 2);
|
||||
|
||||
quest_delete(sd, qid);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
BUILDIN_FUNC(setquestobjective)
|
||||
{
|
||||
|
||||
TBL_PC * sd = script_rid2sd(st);
|
||||
int qid = script_getnum(st, 2);
|
||||
int num = script_getnum(st, 3);
|
||||
const char * str = script_getstr(st, 4);
|
||||
int count = script_getnum(st, 5);
|
||||
|
||||
quest_update_objective(sd, qid, num, str, count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUILDIN_FUNC(hasquest)
|
||||
BUILDIN_FUNC(checkquest)
|
||||
{
|
||||
|
||||
TBL_PC * sd = script_rid2sd(st);
|
||||
int qid = script_getnum(st, 2);
|
||||
quest_check_type type = HAVEQUEST;
|
||||
|
||||
script_pushint(st, quest_has_quest(sd, qid)?1:0);
|
||||
if( script_hasdata(st, 3) )
|
||||
type = (quest_check_type)script_getnum(st, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUILDIN_FUNC(setqueststatus)
|
||||
{
|
||||
|
||||
TBL_PC * sd = script_rid2sd(st);
|
||||
int qid = script_getnum(st, 2);
|
||||
bool active = script_getnum(st, 3)?true:false;
|
||||
|
||||
quest_update_status(sd, qid, active);
|
||||
script_pushint(st, quest_check_quest(sd, script_getnum(st, 2), type));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -14472,11 +14444,6 @@ struct script_function buildin_func[] = {
|
||||
BUILDIN_DEF(openauction,""),
|
||||
BUILDIN_DEF(checkcell,"siii"),
|
||||
BUILDIN_DEF(setcell,"siiiiii"),
|
||||
BUILDIN_DEF(getquest, "ii*"),
|
||||
BUILDIN_DEF(deletequest, "i"),
|
||||
BUILDIN_DEF(setquestobjective, "iisi"),
|
||||
BUILDIN_DEF(setqueststatus, "ii"),
|
||||
BUILDIN_DEF(hasquest, "i"),
|
||||
BUILDIN_DEF(setwall,"siiiiis"),
|
||||
BUILDIN_DEF(delwall,"s"),
|
||||
BUILDIN_DEF(mercenary_create,"ii"),
|
||||
@ -14519,5 +14486,11 @@ struct script_function buildin_func[] = {
|
||||
BUILDIN_DEF(instance_id,"?"),
|
||||
BUILDIN_DEF(instance_warpall,"sii"),
|
||||
BUILDIN_DEF(instance_set_timeout,"ii?"),
|
||||
//Quest Log System [Inkfish]
|
||||
BUILDIN_DEF(setquest, "i"),
|
||||
BUILDIN_DEF(erasequest, "i"),
|
||||
BUILDIN_DEF(completequest, "i"),
|
||||
BUILDIN_DEF(checkquest, "i*"),
|
||||
BUILDIN_DEF(changequest, "ii"),
|
||||
{NULL,NULL,NULL},
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user