diff options
Diffstat (limited to 'src')
21 files changed, 330 insertions, 201 deletions
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h index e849e6620..666d306db 100644 --- a/src/common/HPMDataCheck.h +++ b/src/common/HPMDataCheck.h @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2014-2015 Hercules Dev Team + * Copyright (C) 2014-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -587,6 +587,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = { { "s_autospell", sizeof(struct s_autospell), SERVER_TYPE_MAP }, { "sg_data", sizeof(struct sg_data), SERVER_TYPE_MAP }, { "skill_tree_entry", sizeof(struct skill_tree_entry), SERVER_TYPE_MAP }, + { "skill_tree_requirement", sizeof(struct skill_tree_requirement), SERVER_TYPE_MAP }, { "weapon_data", sizeof(struct weapon_data), SERVER_TYPE_MAP }, #else #define MAP_PC_H diff --git a/src/common/HPMSymbols.inc.h b/src/common/HPMSymbols.inc.h index db9108774..b06c43bf8 100644 --- a/src/common/HPMSymbols.inc.h +++ b/src/common/HPMSymbols.inc.h @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2015-2015 Hercules Dev Team + * Copyright (C) 2015-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/map/atcommand.c b/src/map/atcommand.c index c26daee54..e18b81f44 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -1315,12 +1315,11 @@ ACMD(item2) } if (item_data->type == IT_PETARMOR) refine = 0; - if (refine > MAX_REFINE) - refine = MAX_REFINE; } else { identify = 1; refine = attr = 0; } + refine = cap_value(refine, 0, MAX_REFINE); for (i = 0; i < loop; i++) { memset(&item_tmp, 0, sizeof(item_tmp)); item_tmp.nameid = item_id; @@ -5364,12 +5363,13 @@ ACMD(displayskill) { * @skilltree by [MouseJstr] * prints the skill tree for a player required to get to a skill *------------------------------------------*/ -ACMD(skilltree) { +ACMD(skilltree) +{ struct map_session_data *pl_sd = NULL; uint16 skill_id; int meets, j, c=0; char target[NAME_LENGTH]; - struct skill_tree_entry *ent; + struct skill_tree_entry *entry; if(!*message || sscanf(message, "%5hu %23[^\r\n]", &skill_id, target) != 2) { clif->message(fd, msg_fd(fd,1167)); // Usage: @skilltree <skill ID> <target> @@ -5387,21 +5387,19 @@ ACMD(skilltree) { safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1168), pc->job_name(c), pc->checkskill(pl_sd, NV_BASIC)); // Player is using %s skill tree (%d basic points). clif->message(fd, atcmd_output); - ARR_FIND( 0, MAX_SKILL_TREE, j, pc->skill_tree[c][j].id == 0 || pc->skill_tree[c][j].id == skill_id ); - if( j == MAX_SKILL_TREE || pc->skill_tree[c][j].id == 0 ) - { + ARR_FIND(0, MAX_SKILL_TREE, j, pc->skill_tree[c][j].id == 0 || pc->skill_tree[c][j].id == skill_id); + if (j == MAX_SKILL_TREE || pc->skill_tree[c][j].id == 0) { clif->message(fd, msg_fd(fd,1169)); // The player cannot use that skill. return false; } - ent = &pc->skill_tree[c][j]; + entry = &pc->skill_tree[c][j]; meets = 1; - for(j=0;j<MAX_PC_SKILL_REQUIRE;j++) - { - if( ent->need[j].id && pc->checkskill(sd,ent->need[j].id) < ent->need[j].lv) - { - safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1170), ent->need[j].lv, skill->dbs->db[ent->need[j].id].desc); // Player requires level %d of skill %s. + for (j = 0; j < VECTOR_LENGTH(entry->need); j++) { + struct skill_tree_requirement *req = &VECTOR_INDEX(entry->need, j); + if (pc->checkskill(sd, req->id) < req->lv) { + safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1170), req->lv, skill->dbs->db[req->id].desc); // Player requires level %d of skill %s. clif->message(fd, atcmd_output); meets = 0; } diff --git a/src/map/homunculus.c b/src/map/homunculus.c index ac1c4052b..d81eeb2da 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -227,7 +227,7 @@ int homunculus_calc_skilltree(struct homun_data *hd, int flag_evolve) { if( hd->homunculus.hskill[ id - HM_SKILLBASE ].id ) continue; //Skill already known. if(!battle_config.skillfree) { - for( j = 0; j < MAX_PC_SKILL_REQUIRE; j++ ) { + for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) { if( homun->dbs->skill_tree[c][i].need[j].id && homun->checkskill(hd,homun->dbs->skill_tree[c][i].need[j].id) < homun->dbs->skill_tree[c][i].need[j].lv ) { f = 0; @@ -252,7 +252,7 @@ int homunculus_calc_skilltree(struct homun_data *hd, int flag_evolve) { if( j < homun->dbs->skill_tree[c][i].intimacylv ) continue; if(!battle_config.skillfree) { - for( j = 0; j < MAX_PC_SKILL_REQUIRE; j++ ) { + for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) { if( homun->dbs->skill_tree[c][i].need[j].id && homun->checkskill(hd,homun->dbs->skill_tree[c][i].need[j].id) < homun->dbs->skill_tree[c][i].need[j].lv ) { f = 0; @@ -1234,7 +1234,7 @@ bool homunculus_read_skill_db_sub(char* split[], int columns, int current) { if (minJobLevelPresent) homun->dbs->skill_tree[classid][j].joblv = atoi(split[3]); - for( k = 0; k < MAX_PC_SKILL_REQUIRE; k++ ) { + for (k = 0; k < MAX_HOM_SKILL_REQUIRE; k++) { homun->dbs->skill_tree[classid][j].need[k].id = atoi(split[3+k*2+minJobLevelPresent]); homun->dbs->skill_tree[classid][j].need[k].lv = atoi(split[3+k*2+minJobLevelPresent+1]); } diff --git a/src/map/npc.c b/src/map/npc.c index 09e5c0f46..a7d4cdab0 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2569,8 +2569,7 @@ int npc_parseview(const char* w4, const char* start, const char* buffer, const c } else { // NPC has an ID specified for view id. val = atoi(w4); - if (val != FAKE_NPC) // TODO: Add this to the constants table and replace -1 with FAKE_NPC in the scripts, then remove this check. - ShowWarning("npc_parseview: Use of numeric NPC view IDs is deprecated and may be removed in a future update. Please use NPC view constants instead. ID '%d' specified in file '%s', line '%d'.\n", val, filepath, strline(buffer, start-buffer)); + ShowWarning("npc_parseview: Use of numeric NPC view IDs is deprecated and may be removed in a future update. Please use NPC view constants instead. ID '%d' specified in file '%s', line '%d'.\n", val, filepath, strline(buffer, start-buffer)); } return val; @@ -2947,7 +2946,7 @@ const char* npc_skip_script(const char* start, const char* buffer, const char* f * * Example: * @code - * -<TAB>script<TAB><NPC Name><TAB>-1,{ + * -<TAB>script<TAB><NPC Name><TAB>FAKE_NPC,{ * <code> * } * <map name>,<x>,<y>,<facing><TAB>script<TAB><NPC Name><TAB><sprite id>,{ diff --git a/src/map/pc.c b/src/map/pc.c index d697cd9f4..1045a25be 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -1526,43 +1526,42 @@ int pc_calc_skilltree(struct map_session_data *sd) do { flag = 0; - for( i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++ ) { - int f, idx = pc->skill_tree[c][i].idx; - if( sd->status.skill[idx].id ) + for (i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++) { + int idx = pc->skill_tree[c][i].idx; + bool satisfied = true; + if (sd->status.skill[idx].id > 0) continue; //Skill already known. - f = 1; - if(!battle_config.skillfree) { + if (!battle_config.skillfree) { int j; - for(j = 0; j < MAX_PC_SKILL_REQUIRE; j++) { - int k; - if((k=pc->skill_tree[c][i].need[j].id)) { - int idx2 = pc->skill_tree[c][i].need[j].idx; - if (sd->status.skill[idx2].id == 0 || sd->status.skill[idx2].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[idx2].flag == SKILL_FLAG_PLAGIARIZED) - k = 0; //Not learned. - else if (sd->status.skill[idx2].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level - k = sd->status.skill[idx2].flag - SKILL_FLAG_REPLACED_LV_0; - else - k = pc->checkskill2(sd,idx2); - if (k < pc->skill_tree[c][i].need[j].lv) { - f = 0; - break; - } + for (j = 0; j < VECTOR_LENGTH(pc->skill_tree[c][i].need); j++) { + struct skill_tree_requirement *req = &VECTOR_INDEX(pc->skill_tree[c][i].need, j); + int level; + if (sd->status.skill[req->idx].id == 0 + || sd->status.skill[req->idx].flag == SKILL_FLAG_TEMPORARY + || sd->status.skill[req->idx].flag == SKILL_FLAG_PLAGIARIZED) + level = 0; //Not learned. + else if (sd->status.skill[req->idx].flag >= SKILL_FLAG_REPLACED_LV_0) //Real learned level + level = sd->status.skill[req->idx].flag - SKILL_FLAG_REPLACED_LV_0; + else + level = pc->checkskill2(sd, req->idx); + if (level < req->lv) { + satisfied = false; + break; } } - if ( sd->status.job_level < pc->skill_tree[c][i].joblv ) { - int x = pc->mapid2jobid(sd->class_, sd->status.sex); // need to get its own skilltree - if ( x > -1 ) { - x = pc->class2idx(x); - if ( !pc->skill_tree[x][i].inherited ) - f = 0; // job level requirement wasn't satisfied - } else - f = 0; + if (sd->status.job_level < pc->skill_tree[c][i].joblv) { + int jobid = pc->mapid2jobid(sd->class_, sd->status.sex); // need to get its own skilltree + if (jobid > -1) { + if (!pc->skill_tree[pc->class2idx(jobid)][i].inherited) + satisfied = false; // job level requirement wasn't satisfied + } else { + satisfied = false; + } } } - if( f ) { - int inf2; - inf2 = skill->dbs->db[idx].inf2; + if (satisfied) { + int inf2 = skill->dbs->db[idx].inf2; if(!sd->status.skill[idx].lv && ( (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || @@ -1628,39 +1627,40 @@ void pc_check_skilltree(struct map_session_data *sd, int skill_id) c = pc->class2idx(c); do { flag = 0; - for (i = 0; i < MAX_SKILL_TREE && (id=pc->skill_tree[c][i].id)>0; i++) { - int j, f = 1, idx = pc->skill_tree[c][i].idx; + for (i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++) { + int j, idx = pc->skill_tree[c][i].idx; + bool satisfied = true; - if( sd->status.skill[idx].id ) //Already learned + if (sd->status.skill[idx].id) //Already learned continue; - for (j = 0; j < MAX_PC_SKILL_REQUIRE; j++) { - int k = pc->skill_tree[c][i].need[j].id; - if (k) { - int idx2 = pc->skill_tree[c][i].need[j].idx; - if (sd->status.skill[idx2].id == 0 || sd->status.skill[idx2].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[idx2].flag == SKILL_FLAG_PLAGIARIZED) - k = 0; //Not learned. - else if (sd->status.skill[idx2].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level - k = sd->status.skill[idx2].flag - SKILL_FLAG_REPLACED_LV_0; - else - k = pc->checkskill2(sd,idx2); - if (k < pc->skill_tree[c][i].need[j].lv) { - f = 0; - break; - } + for (j = 0; j < VECTOR_LENGTH(pc->skill_tree[c][i].need); j++) { + struct skill_tree_requirement *req = &VECTOR_INDEX(pc->skill_tree[c][i].need, j); + int level; + if (sd->status.skill[req->idx].id == 0 + || sd->status.skill[req->idx].flag == SKILL_FLAG_TEMPORARY + || sd->status.skill[req->idx].flag == SKILL_FLAG_PLAGIARIZED) + level = 0; //Not learned. + else if (sd->status.skill[req->idx].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level + level = sd->status.skill[req->idx].flag - SKILL_FLAG_REPLACED_LV_0; + else + level = pc->checkskill2(sd,req->idx); + if (level < req->lv) { + satisfied = false; + break; } } - if( !f ) + if (!satisfied) continue; - if ( sd->status.job_level < pc->skill_tree[c][i].joblv ) { - int x = pc->mapid2jobid(sd->class_, sd->status.sex); // need to get its own skilltree - if ( x > -1 ) { - x = pc->class2idx(x); - if ( !pc->skill_tree[x][i].inherited ) + if (sd->status.job_level < pc->skill_tree[c][i].joblv) { + int jobid = pc->mapid2jobid(sd->class_, sd->status.sex); // need to get its own skilltree + if (jobid > -1) { + if (!pc->skill_tree[pc->class2idx(jobid)][i].inherited) continue; - } else + } else { continue; + } } j = skill->dbs->db[idx].inf2; @@ -10592,128 +10592,203 @@ int pc_split_atoui(char* str, unsigned int* val, char sep, int max) val[j] = 0; return i; } -/* [Ind/Hercules] */ -void pc_read_skill_tree(void) { + +/** + * Parses the skill tree config file. + * + * In order to reclaim the memory allocated by this function + * `pc->clear_skill_tree()` should be used. + * + * @remark + * This function assumes that the skill tree is clear and zeroed. + * If it has been already loaded (ie reloading), it needs to be cleared + * before calling this function again. + * + * @author [Ind/Hercules] + */ +void pc_read_skill_tree(void) +{ config_t skill_tree_conf; - config_setting_t *skt = NULL, *inherit = NULL, *skills = NULL, *sk = NULL; -#ifdef RENEWAL - const char *config_filename = "db/re/skill_tree.conf"; // FIXME hardcoded name -#else - const char *config_filename = "db/pre-re/skill_tree.conf"; // FIXME hardcoded name -#endif + config_setting_t *skt = NULL; + char config_filename[128]; int i = 0; struct s_mapiterator *iter; struct map_session_data *sd; + bool loaded[CLASS_COUNT] = { false }; + safesnprintf(config_filename, sizeof(config_filename), "%s/"DBPATH"skill_tree.conf", map->db_path); if (libconfig->read_file(&skill_tree_conf, config_filename)) { ShowError("can't read %s\n", config_filename); return; } - while ((skt = libconfig->setting_get_elem(skill_tree_conf.root,i++))) { - int k; - const char *name = config_setting_name(skt); + // Foreach job + while ((skt = libconfig->setting_get_elem(skill_tree_conf.root, i++))) { + config_setting_t *t = NULL; + int job_idx; + const char *job_name = config_setting_name(skt); + int job_id = pc->check_job_name(job_name); - if ( (k = pc->check_job_name(name)) == -1 ) { - ShowWarning("pc_read_skill_tree: '%s' unknown job name!\n", name); + if (job_id == -1) { + ShowWarning("pc_read_skill_tree: '%s' unknown job name!\n", job_name); + continue; + } + job_idx = pc->class2idx(job_id); + if (loaded[job_idx]) { + ShowWarning("pc_read_skill_tree: Duplicate entry for job '%s'. Skipping.\n", job_name); continue; } + loaded[job_idx] = true; - if( ( skills = libconfig->setting_get_member(skt,"skills") ) ) { - int c = 0; - int idx = pc->class2idx(k); + if ((t = libconfig->setting_get_member(skt, "inherit")) != NULL) { + int j = 0; + const char *ijob_name = NULL; + // Foreach inherited job + while ((ijob_name = libconfig->setting_get_string_elem(t, j++)) != NULL) { + int k, ijob_idx; + int ijob_id = pc->check_job_name(ijob_name); - while ((sk = libconfig->setting_get_elem(skills,c++))) { - const char *sk_name = config_setting_name(sk); - int skill_id; + if (ijob_id == -1) { + ShowWarning("pc_read_skill_tree: '%s' trying to inherit unknown '%s'!\n", job_name, ijob_name); + continue; + } + ijob_idx = pc->class2idx(ijob_id); + if (ijob_idx == job_idx) { + ShowWarning("pc_read_skill_tree: '%s' trying to inherit itself. Skipping.\n", job_name); + continue; + } + if (!loaded[ijob_idx]) { + ShowWarning("pc_read_skill_tree: '%s' trying to inherit not yet loaded '%s' (wrong order in the tree). Skipping.\n", job_name, ijob_name); + continue; + } - if( ( skill_id = skill->name2id(sk_name) ) ) { - int skidx, offset = 0, h = 0, rlen = 0; + for (k = 0; k < MAX_SKILL_TREE; k++) { + int cur; + struct skill_tree_entry *dst = NULL; + const struct skill_tree_entry *src = &pc->skill_tree[ijob_idx][k]; - ARR_FIND( 0, MAX_SKILL_TREE, skidx, pc->skill_tree[idx][skidx].id == 0 || pc->skill_tree[idx][skidx].id == skill_id ); - if (skidx == MAX_SKILL_TREE) { - ShowWarning("pc_read_skill_tree: Unable to load skill %d (%s) into '%s's tree. Maximum number of skills per class has been reached.\n", skill_id, sk_name, name); - continue; - } else if (pc->skill_tree[idx][skidx].id) { - ShowNotice("pc_read_skill_tree: Overwriting %d for '%s' (%d)\n", skill_id, name, k); - } + if (src->id == 0) + break; // No more skills to copy - pc->skill_tree[idx][skidx].id = skill_id; - pc->skill_tree[idx][skidx].idx = skill->get_index(skill_id); - - if( config_setting_is_group(sk) ) { - int max = 0, jlevel = 0; - libconfig->setting_lookup_int(sk, "MaxLevel", &max); - libconfig->setting_lookup_int(sk, "MinJobLevel", &jlevel); - pc->skill_tree[idx][skidx].max = (unsigned char)max; - pc->skill_tree[idx][skidx].joblv = (unsigned char)jlevel; - rlen = libconfig->setting_length(sk); - offset += jlevel ? 2 : 1; - } else { - pc->skill_tree[idx][skidx].max = (unsigned char)libconfig->setting_get_int(sk); - pc->skill_tree[idx][skidx].joblv = 0; + ARR_FIND(0, MAX_SKILL_TREE, cur, pc->skill_tree[job_idx][cur].id == 0 || pc->skill_tree[job_idx][cur].id == src->id); + if (cur == MAX_SKILL_TREE) { + ShowWarning("pc_read_skill_tree: '%s' can't inherit '%s', skill tree is full!\n", job_name, ijob_name); + break; } - - for (h = offset; h < rlen && h < MAX_PC_SKILL_REQUIRE; h++) { - config_setting_t *rsk = libconfig->setting_get_elem(sk,h); - int rskid; - if (rsk && (rskid = skill->name2id(config_setting_name(rsk))) != 0) { - pc->skill_tree[idx][skidx].need[h].id = rskid; - pc->skill_tree[idx][skidx].need[h].idx = skill->get_index(rskid); - pc->skill_tree[idx][skidx].need[h].lv = (unsigned char)libconfig->setting_get_int(rsk); - } else if( rsk ) { - ShowWarning("pc_read_skill_tree: unknown requirement '%s' for '%s' in '%s'\n",config_setting_name(rsk),sk_name,name); - } else { - ShowWarning("pc_read_skill_tree: error for '%s' in '%s'\n",sk_name,name); + if (src->id == NV_TRICKDEAD && ((pc->jobid2mapid(job_id)&(MAPID_BASEMASK | JOBL_2)) != MAPID_NOVICE)) + continue; // skip trickdead for non-novices + dst = &pc->skill_tree[job_idx][cur]; + dst->inherited = 1; + if (dst->id == 0) { + // Not existing yet, copy + dst->id = src->id; + dst->idx = src->idx; + dst->max = src->max; + dst->joblv = src->joblv; + VECTOR_INIT(dst->need); + if (VECTOR_LENGTH(src->need) > 0) { + VECTOR_ENSURE(dst->need, VECTOR_LENGTH(src->need), 1); + VECTOR_PUSHARRAY(dst->need, VECTOR_DATA(src->need), VECTOR_LENGTH(src->need)); + } + } else { + int l; + // Already existing, merge + if (src->max > dst->max) + dst->max = src->max; + dst->joblv = src->joblv; + for (l = 0; l < VECTOR_LENGTH(src->need); l++) { + int m; + struct skill_tree_requirement *sreq = &VECTOR_INDEX(src->need, l); + ARR_FIND(0, VECTOR_LENGTH(dst->need), m, VECTOR_INDEX(dst->need, m).id == sreq->id); + if (m == VECTOR_LENGTH(dst->need)) { + VECTOR_ENSURE(dst->need, 1, 1); + VECTOR_PUSHCOPY(dst->need, sreq); + } else { + struct skill_tree_requirement *dreq = &VECTOR_INDEX(dst->need, m); + dreq->lv = sreq->lv; + } } } - } else { - ShowWarning("pc_read_skill_tree: unknown skill '%s' in '%s'\n",sk_name,name); } } } - } - - i = 0; - while( (skt = libconfig->setting_get_elem(skill_tree_conf.root,i++)) ) { - int k, idx; - const char *name = config_setting_name(skt); - - if ( (k = pc->check_job_name(name)) == -1 ) { - ShowWarning("pc_read_skill_tree: '%s' unknown job name!\n", name); - continue; - } - - idx = pc->class2idx(k); - - if( ( inherit = libconfig->setting_get_member(skt,"inherit") ) ) { - const char *iname; - int v = 0; - while ( (iname = libconfig->setting_get_string_elem(inherit, v++)) ) { - int b = 0, a, d, f, fidx; + if ((t = libconfig->setting_get_member(skt, "skills")) != NULL) { + int j = 0; + config_setting_t *sk = NULL; + // Foreach skill + while ((sk = libconfig->setting_get_elem(t, j++)) != NULL) { + int skill_id, sk_idx; + config_setting_t *rsk = NULL; + const char *sk_name = config_setting_name(sk); + struct skill_tree_entry *tree_entry = NULL; - if ( (b = pc->check_job_name(iname)) == -1 ) { - ShowWarning("pc_read_skill_tree: '%s' trying to inherit unknown '%s'!\n", name, iname); + if ((skill_id = skill->name2id(sk_name)) == 0) { + ShowWarning("pc_read_skill_tree: unknown skill '%s' in '%s'\n", sk_name, job_name); continue; } - fidx = pc->class2idx(b); - - ARR_FIND(0, MAX_SKILL_TREE, d, pc->skill_tree[fidx][d].id == 0); - - for ( f = 0; f < d; f++ ) { - - ARR_FIND(0, MAX_SKILL_TREE, a, pc->skill_tree[idx][a].id == 0 || pc->skill_tree[idx][a].id == pc->skill_tree[fidx][f].id); + ARR_FIND(0, MAX_SKILL_TREE, sk_idx, pc->skill_tree[job_idx][sk_idx].id == 0 || pc->skill_tree[job_idx][sk_idx].id == skill_id); + if (sk_idx == MAX_SKILL_TREE) { + ShowWarning("pc_read_skill_tree: Unable to load skill %d (%s) into '%s's tree. Maximum number of skills per class has been reached.\n", skill_id, sk_name, job_name); + continue; + } + tree_entry = &pc->skill_tree[job_idx][sk_idx]; - if ( a == MAX_SKILL_TREE ) { - ShowWarning("pc_read_skill_tree: '%s' can't inherit '%s', skill tree is full!\n", name, iname); - break; - } else if ( pc->skill_tree[idx][a].id || (pc->skill_tree[idx][a].id == NV_TRICKDEAD && ((pc->jobid2mapid(k)&(MAPID_BASEMASK | JOBL_2)) != MAPID_NOVICE)) ) /* we skip trickdead for non-novices */ - continue;/* skip */ - memcpy(&pc->skill_tree[idx][a], &pc->skill_tree[fidx][f], sizeof(pc->skill_tree[fidx][f])); - pc->skill_tree[idx][a].inherited = 1; + if (tree_entry->id != 0 && !tree_entry->inherited) { + ShowNotice("pc_read_skill_tree: Duplicate %d for '%s' (%d). Skipping.\n", skill_id, job_name, job_id); + continue; + } + if (config_setting_is_group(sk)) { + int i32 = 0; + if (libconfig->setting_lookup_int(sk, "MaxLevel", &i32) && i32 > 0) { + tree_entry->max = (unsigned char)i32; + } else { + ShowWarning("pc_read_skill_tree: missing MaxLevel for skill %d (%s) class '%s'. Skipping.\n", skill_id, sk_name, job_name); + continue; + } + if (libconfig->setting_lookup_int(sk, "MinJobLevel", &i32) && i32 > 0) { + tree_entry->joblv = (unsigned char)i32; + } else if (!tree_entry->inherited) { + tree_entry->joblv = 0; + } + } else { + tree_entry->max = (unsigned char)libconfig->setting_get_int(sk); + if (!tree_entry->inherited) + tree_entry->joblv = 0; + } + if (!tree_entry->inherited) { + tree_entry->id = skill_id; + tree_entry->idx = skill->get_index(skill_id); + VECTOR_INIT(tree_entry->need); } + if (config_setting_is_group(sk)) { + int k = 0; + // Foreach requirement + while ((rsk = libconfig->setting_get_elem(sk, k++)) != NULL) { + const char *rsk_name = config_setting_name(rsk); + int rsk_id = skill->name2id(rsk_name); + struct skill_tree_requirement *req = NULL; + int l; + + if (rsk_id == 0) { + if (strcmp(rsk_name, "MaxLevel") != 0 && strcmp(rsk_name, "MinJobLevel") != 0) + ShowWarning("pc_read_skill_tree: unknown requirement '%s' for '%s' in '%s'\n", rsk_name, sk_name, job_name); + continue; + } + ARR_FIND(0, VECTOR_LENGTH(tree_entry->need), l, VECTOR_INDEX(tree_entry->need, l).id == rsk_id); + if (l == VECTOR_LENGTH(tree_entry->need)) { + VECTOR_ENSURE(tree_entry->need, 1, 1); + VECTOR_PUSHZEROED(tree_entry->need); + req = &VECTOR_LAST(tree_entry->need); + req->id = rsk_id; + req->idx = skill->get_index(rsk_id); + } else { + req = &VECTOR_INDEX(tree_entry->need, l); + } + req->lv = (unsigned char)libconfig->setting_get_int(rsk); + } + } } } } @@ -10726,6 +10801,24 @@ void pc_read_skill_tree(void) { clif->skillinfoblock(sd); mapit->free(iter); } + +/** + * Clears the skill tree and frees any allocated memory. + */ +void pc_clear_skill_tree(void) +{ + int i; + for (i = 0; i < CLASS_COUNT; i++) { + int j; + for (j = 0; j < MAX_SKILL_TREE; j++) { + if (pc->skill_tree[i][j].id == 0) + continue; + VECTOR_CLEAR(pc->skill_tree[i][j].need); + } + } + memset(pc->skill_tree, 0, sizeof(pc->skill_tree)); +} + bool pc_readdb_levelpenalty(char* fields[], int columns, int current) { #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) int type, race, diff; @@ -10842,7 +10935,7 @@ int pc_readdb(void) { ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"exp.txt"); count = 0; // Reset and read skilltree - memset(pc->skill_tree,0,sizeof(pc->skill_tree)); + pc->clear_skill_tree(); pc->read_skill_tree(); #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) sv->readdb(map->db_path, "re/level_penalty.txt", ',', 4, 4, -1, pc->readdb_levelpenalty); @@ -11367,6 +11460,8 @@ void do_final_pc(void) { pcg->final(); + pc->clear_skill_tree(); + ers_destroy(pc->sc_display_ers); ers_destroy(pc->num_reg_ers); ers_destroy(pc->str_reg_ers); @@ -11693,6 +11788,7 @@ void pc_defaults(void) { pc->autosave = pc_autosave; pc->follow_timer = pc_follow_timer; pc->read_skill_tree = pc_read_skill_tree; + pc->clear_skill_tree = pc_clear_skill_tree; pc->isUseitem = pc_isUseitem; pc->show_steal = pc_show_steal; pc->checkcombo = pc_checkcombo; diff --git a/src/map/pc.h b/src/map/pc.h index 97f339bf6..23b46a631 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -41,7 +41,6 @@ * Defines **/ #define MAX_PC_BONUS 10 -#define MAX_PC_SKILL_REQUIRE 5 #define MAX_PC_FEELHATE 3 #define MAX_PC_DEVOTION 5 ///< Max amount of devotion targets #define PVP_CALCRANK_INTERVAL 1000 ///< PVP calculation interval @@ -714,17 +713,19 @@ END_ZEROED_BLOCK; #define pc_can_give_items(sd) ( pc_has_permission((sd),PC_PERM_TRADE) ) #define pc_can_give_bound_items(sd) ( pc_has_permission((sd),PC_PERM_TRADE_BOUND) ) +struct skill_tree_requirement { + short id; + unsigned short idx; + unsigned char lv; +}; + struct skill_tree_entry { short id; unsigned short idx; unsigned char max; unsigned char joblv; short inherited; - struct { - short id; - unsigned short idx; - unsigned char lv; - } need[MAX_PC_SKILL_REQUIRE]; + VECTOR_DECL(struct skill_tree_requirement) need; }; // Celest struct sg_data { @@ -1052,6 +1053,7 @@ END_ZEROED_BLOCK; /* End */ int (*autosave) (int tid, int64 tick, int id, intptr_t data); int (*follow_timer) (int tid, int64 tick, int id, intptr_t data); void (*read_skill_tree) (void); + void (*clear_skill_tree) (void); int (*isUseitem) (struct map_session_data *sd,int n); int (*show_steal) (struct block_list *bl,va_list ap); int (*checkcombo) (struct map_session_data *sd, struct item_data *data ); diff --git a/src/map/script.c b/src/map/script.c index 591bca68f..c48758db3 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -7253,7 +7253,7 @@ BUILDIN(getitem2) if (item_data == NULL) return -1; if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR) { - if(ref > MAX_REFINE) ref = MAX_REFINE; + ref = cap_value(ref, 0, MAX_REFINE); } else if(item_data->type==IT_PETEGG) { iden = 1; diff --git a/src/map/skill.c b/src/map/skill.c index dc3ebe62e..6795707fd 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -19082,22 +19082,24 @@ void skill_readdb(bool minimal) { sv->readdb(map->db_path, "skill_changematerial_db.txt", ',', 4, 4+2*5, MAX_SKILL_PRODUCE_DB, skill->parse_row_changematerialdb); } -void skill_reload (void) { +void skill_reload(void) +{ struct s_mapiterator *iter; struct map_session_data *sd; - int i,c,k; + int i, j, k; skill->read_db(false); //[Ind/Hercules] refresh index cache - for(c = 0; c < CLASS_COUNT; c++) { - for( i = 0; i < MAX_SKILL_TREE; i++ ) { - if( pc->skill_tree[c][i].id ) { - pc->skill_tree[c][i].idx = skill->get_index(pc->skill_tree[c][i].id); - for(k = 0; k < MAX_PC_SKILL_REQUIRE; k++) { - if( pc->skill_tree[c][i].need[k].id ) - pc->skill_tree[c][i].need[k].idx = skill->get_index(pc->skill_tree[c][i].need[k].id); - } + for (j = 0; j < CLASS_COUNT; j++) { + for (i = 0; i < MAX_SKILL_TREE; i++) { + struct skill_tree_entry *entry = &pc->skill_tree[j][i]; + if (entry->id == 0) + continue; + entry->idx = skill->get_index(entry->id); + for (k = 0; k < VECTOR_LENGTH(entry->need); k++) { + struct skill_tree_requirement *req = &VECTOR_INDEX(entry->need, k); + req->idx = skill->get_index(req->id); } } } diff --git a/src/plugins/HPMHooking/HPMHooking_char.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_char.HPMHooksCore.inc index aefb3aa93..dd6b3d5d6 100644 --- a/src/plugins/HPMHooking/HPMHooking_char.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_char.HPMHooksCore.inc @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/plugins/HPMHooking/HPMHooking_char.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_char.HookingPoints.inc index 3c442c4ab..34a9e4005 100644 --- a/src/plugins/HPMHooking/HPMHooking_char.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_char.HookingPoints.inc @@ -1,7 +1,7 @@ /** * This file is part of Hercules. * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc index 3e9e6e1d2..b1554aefd 100644 --- a/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/plugins/HPMHooking/HPMHooking_char.sources.inc b/src/plugins/HPMHooking/HPMHooking_char.sources.inc index 92623f516..d14117add 100644 --- a/src/plugins/HPMHooking/HPMHooking_char.sources.inc +++ b/src/plugins/HPMHooking/HPMHooking_char.sources.inc @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/plugins/HPMHooking/HPMHooking_login.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_login.HPMHooksCore.inc index 5540e15b3..3a8bb2a5f 100644 --- a/src/plugins/HPMHooking/HPMHooking_login.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_login.HPMHooksCore.inc @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/plugins/HPMHooking/HPMHooking_login.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_login.HookingPoints.inc index 27e0f857d..959bb076f 100644 --- a/src/plugins/HPMHooking/HPMHooking_login.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_login.HookingPoints.inc @@ -1,7 +1,7 @@ /** * This file is part of Hercules. * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/plugins/HPMHooking/HPMHooking_login.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_login.Hooks.inc index 012240bb3..2e2d9e619 100644 --- a/src/plugins/HPMHooking/HPMHooking_login.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_login.Hooks.inc @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/plugins/HPMHooking/HPMHooking_login.sources.inc b/src/plugins/HPMHooking/HPMHooking_login.sources.inc index 38500f0ee..bbc1cecbc 100644 --- a/src/plugins/HPMHooking/HPMHooking_login.sources.inc +++ b/src/plugins/HPMHooking/HPMHooking_login.sources.inc @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index c725cdf4a..ccc908c33 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -4262,6 +4262,8 @@ struct { struct HPMHookPoint *HP_pc_follow_timer_post; struct HPMHookPoint *HP_pc_read_skill_tree_pre; struct HPMHookPoint *HP_pc_read_skill_tree_post; + struct HPMHookPoint *HP_pc_clear_skill_tree_pre; + struct HPMHookPoint *HP_pc_clear_skill_tree_post; struct HPMHookPoint *HP_pc_isUseitem_pre; struct HPMHookPoint *HP_pc_isUseitem_post; struct HPMHookPoint *HP_pc_show_steal_pre; @@ -10089,6 +10091,8 @@ struct { int HP_pc_follow_timer_post; int HP_pc_read_skill_tree_pre; int HP_pc_read_skill_tree_post; + int HP_pc_clear_skill_tree_pre; + int HP_pc_clear_skill_tree_post; int HP_pc_isUseitem_pre; int HP_pc_isUseitem_post; int HP_pc_show_steal_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index 456f2985f..514a79ba1 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -1,7 +1,7 @@ /** * This file is part of Hercules. * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -2181,6 +2181,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(pc->autosave, HP_pc_autosave) }, { HP_POP(pc->follow_timer, HP_pc_follow_timer) }, { HP_POP(pc->read_skill_tree, HP_pc_read_skill_tree) }, + { HP_POP(pc->clear_skill_tree, HP_pc_clear_skill_tree) }, { HP_POP(pc->isUseitem, HP_pc_isUseitem) }, { HP_POP(pc->show_steal, HP_pc_show_steal) }, { HP_POP(pc->checkcombo, HP_pc_checkcombo) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index ad9d96f03..96956f753 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56817,6 +56817,32 @@ void HP_pc_read_skill_tree(void) { } return; } +void HP_pc_clear_skill_tree(void) { + int hIndex = 0; + if( HPMHooks.count.HP_pc_clear_skill_tree_pre ) { + void (*preHookFunc) (void); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_clear_skill_tree_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_pc_clear_skill_tree_pre[hIndex].func; + preHookFunc(); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.pc.clear_skill_tree(); + } + if( HPMHooks.count.HP_pc_clear_skill_tree_post ) { + void (*postHookFunc) (void); + for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_clear_skill_tree_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_pc_clear_skill_tree_post[hIndex].func; + postHookFunc(); + } + } + return; +} int HP_pc_isUseitem(struct map_session_data *sd, int n) { int hIndex = 0; int retVal___ = 0; diff --git a/src/plugins/HPMHooking/HPMHooking_map.sources.inc b/src/plugins/HPMHooking/HPMHooking_map.sources.inc index bab4f3931..1af35ab21 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.sources.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.sources.inc @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by |