From ce070c5d8303a15fec032721e0163bdce4e84c33 Mon Sep 17 00:00:00 2001 From: celest Date: Sun, 20 Feb 2005 14:11:43 +0000 Subject: * Added skill requirements for the new guild skills * Allow Emergency Recall to be cast in guild castles * Add 'minimum job level required' for skill_tree reading - Berserk now requires job level 50 * Added Spring Trap to be able to trigger ankle snare traps that aren't activated yet * Added a fix in guild.c by Mellowz * Some rewrites on the pet skill bonuses system * Check whether a monster is still alive before starting a status change git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/branches/stable@1142 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/clif.c | 70 ++++++++++++++++++++++++++------------------ src/map/guild.c | 10 ++++--- src/map/map.h | 4 ++- src/map/pc.c | 62 +++++++++++++++++---------------------- src/map/pc.h | 1 + src/map/pet.c | 89 ++++++++++++++++++++------------------------------------ src/map/pet.h | 2 -- src/map/script.c | 13 +++++++-- src/map/skill.c | 18 +++++++++--- src/map/status.c | 22 ++++++++++++-- src/map/status.h | 2 ++ 11 files changed, 154 insertions(+), 139 deletions(-) (limited to 'src') diff --git a/src/map/clif.c b/src/map/clif.c index 1d4a7a437..f649093db 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -6680,35 +6680,47 @@ int clif_guild_skillinfo(struct map_session_data *sd) memset(WFIFOP(fd,c*37+18),0,24); if(g->skill[i].lv < guild_skill_get_max(id)) { //Kafra and Guardian changed to require Approval [Sara] - if (g->skill[i].id == GD_KAFRACONTACT && guild_checkskill(g,GD_APPROVAL) <= 0) - up = 0; - else if (g->skill[i].id == GD_GUARDIANRESEARCH && guild_checkskill(g,GD_APPROVAL) <= 0) - up = 0; - //Glory skill requirements -- Pretty sure correct [Sara] - else if (g->skill[i].id == GD_LEADERSHIP && guild_checkskill(g,GD_GLORYGUILD) <= 0) - up = 0; - else if (g->skill[i].id == GD_GLORYWOUNDS && guild_checkskill(g,GD_GLORYGUILD) <= 0) - up = 0; - else if (g->skill[i].id == GD_SOULCOLD && guild_checkskill(g,GD_GLORYWOUNDS) <= 0) - up = 0; - else if (g->skill[i].id == GD_HAWKEYES && guild_checkskill(g,GD_LEADERSHIP) <= 0) - up = 0; - //Activated skill requirements -- Just guesses [Sara] - else if (g->skill[i].id == GD_BATTLEORDER && guild_checkskill(g,GD_APPROVAL) <= 0) - up = 0; - else if (g->skill[i].id == GD_REGENERATION && guild_checkskill(g,GD_APPROVAL) <= 0) - up = 0; - else if (g->skill[i].id == GD_RESTORE && guild_checkskill(g,GD_REGENERATION) <= 0) - up = 0; - else if (g->skill[i].id == GD_EMERGENCYCALL && guild_checkskill(g,GD_APPROVAL) <= 0) - up = 0; - if (g->skill[i].id == GD_GUARDUP && guild_checkskill(g,GD_GUARDIANRESEARCH) <= 0) - up = 0; - //Unadded yet? Has extension description in kRO tables - else if (g->skill[i].id == GD_DEVELOPMENT) - up = 0; - else - up = 1; + switch (g->skill[i].id) + { + case GD_KAFRACONTACT: + case GD_GUARDIANRESEARCH: + case GD_GUARDUP: + up = guild_checkskill(g,GD_APPROVAL) > 0; + break; + case GD_LEADERSHIP: + //Glory skill requirements -- Pretty sure correct [Sara] + up = guild_checkskill(g,GD_GLORYGUILD) > 0; + break; + case GD_GLORYWOUNDS: + up = guild_checkskill(g,GD_GLORYGUILD) > 0; + break; + case GD_SOULCOLD: + up = guild_checkskill(g,GD_GLORYWOUNDS) > 0; + break; + case GD_HAWKEYES: + up = guild_checkskill(g,GD_LEADERSHIP) > 0; + break; + case GD_BATTLEORDER: + up = guild_checkskill(g,GD_APPROVAL) > 0 && + guild_checkskill(g,GD_EXTENSION) >= 2; + break; + case GD_REGENERATION: + up = guild_checkskill(g,GD_EXTENSION) >= 5 && + guild_checkskill(g,GD_BATTLEORDER) > 0; + break; + case GD_RESTORE: + up = guild_checkskill(g,GD_REGENERATION) >= 2; + break; + case GD_EMERGENCYCALL: + up = guild_checkskill(g,GD_GUARDIANRESEARCH) > 0 && + guild_checkskill(g,GD_REGENERATION) > 0; + break; + case GD_DEVELOPMENT: + up = 0; + break; + default: + up = 1; + } } else { up = 0; diff --git a/src/map/guild.c b/src/map/guild.c index ed3eda3ba..d0d7f14dd 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -696,10 +696,12 @@ int guild_member_leaved(int guild_id,int account_id,int char_id,int flag, g->member[i].sd=NULL; } } - if(sd!=NULL && sd->status.guild_id==guild_id){ - sd->status.guild_id=0; - sd->guild_emblem_id=0; - sd->guild_sended=0; + if(sd!=NULL) { + if (sd->status.guild_id==guild_id){ + sd->status.guild_id=0; + sd->guild_emblem_id=0; + sd->guild_sended=0; + } } // メンバーリストを全員に再通知 diff --git a/src/map/map.h b/src/map/map.h index 99bceb884..92c334806 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -485,6 +485,7 @@ struct pet_data { unsigned state : 8 ; unsigned skillstate : 8 ; unsigned change_walk_target : 1 ; + short skillbonus; } state; int timer; short to_x,to_y; @@ -495,7 +496,8 @@ struct pet_data { int move_fail_count; unsigned int attackabletime,next_walktime,last_thinktime; int skilltype,skillval,skilltimer,skillduration; // [Valaris] - int skillbonustype,skillbonusval,skillbonustimer,skillbonusduration; // [Valaris] + //int skillbonustype,skillbonusval,skillbonustimer,skillbonusduration; // [Valaris] + int skillbonustype,skillbonusval,skillbonustimer; struct item *lootitem; short loot; // [Valaris] short lootmax; // [Valaris] diff --git a/src/map/pc.c b/src/map/pc.c index 4b2131f57..fc67196d5 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -747,7 +747,7 @@ int pc_authok(int id, int login_id2, time_t connect_until_time, struct mmo_chars // スキルユニット?係の初期化 memset(sd->skillunit, 0, sizeof(sd->skillunit)); - memset(sd->skillunittick, 0, sizeof(sd->skillunittick)); + memset(sd->skillunittick, 0, sizeof(sd->skillunittick)); // パ?ティ??係の初期化 sd->party_sended = 0; @@ -989,23 +989,25 @@ int pc_calc_skilltree(struct map_session_data *sd) for(i=0;(id=skill_tree[s][c][i].id)>0;i++){ int j,f=1; if(!battle_config.skillfree) { - for(j=0;j<5;j++) { - if( skill_tree[s][c][i].need[j].id && - pc_checkskill(sd,skill_tree[s][c][i].need[j].id) < - skill_tree[s][c][i].need[j].lv) { - f=0; + for(j=0;j<5;j++) { + if( skill_tree[s][c][i].need[j].id && + pc_checkskill(sd,skill_tree[s][c][i].need[j].id) < + skill_tree[s][c][i].need[j].lv) { + f=0; break; } - } - if (id >= 2 && id <= 53 && pc_checkskill(sd, NV_BASIC) < 9) + } + if (sd->status.job_level < skill_tree[s][c][i].joblv) f=0; - } - if(f && sd->status.skill[id].id==0 ){ - sd->status.skill[id].id=id; - flag=1; - } - } - } while(flag); + if (id >= 2 && id <= 53 && pc_checkskill(sd, NV_BASIC) < 9) + f=0; + } + if(f && sd->status.skill[id].id==0 ){ + sd->status.skill[id].id=id; + flag=1; + } + } + } while(flag); } // if(battle_config.etc_log) // printf("calc skill_tree\n"); @@ -1493,20 +1495,12 @@ int pc_bonus(struct map_session_data *sd,int type,int val) sd->parame[SP_INT-SP_STR]+=val; sd->parame[SP_DEX-SP_STR]+=val; sd->parame[SP_LUK-SP_STR]+=val; - clif_updatestatus(sd,13); - clif_updatestatus(sd,14); - clif_updatestatus(sd,15); - clif_updatestatus(sd,16); - clif_updatestatus(sd,17); - clif_updatestatus(sd,18); } break; case SP_AGI_VIT: // [Valaris] if(sd->state.lr_flag!=2) { sd->parame[SP_AGI-SP_STR]+=val; sd->parame[SP_VIT-SP_STR]+=val; - clif_updatestatus(sd,14); - clif_updatestatus(sd,15); } break; case SP_AGI_DEX_STR: // [Valaris] @@ -1514,9 +1508,6 @@ int pc_bonus(struct map_session_data *sd,int type,int val) sd->parame[SP_AGI-SP_STR]+=val; sd->parame[SP_DEX-SP_STR]+=val; sd->parame[SP_STR-SP_STR]+=val; - clif_updatestatus(sd,14); - clif_updatestatus(sd,17); - clif_updatestatus(sd,13); } break; case SP_PERFECT_HIDE: // [Valaris] @@ -7024,16 +7015,20 @@ int pc_readdb(void) while(fgets(line, sizeof(line)-1, fp)){ char *split[50]; + int f=0, m=3; if(line[0]=='/' && line[1]=='/') continue; - for(j=0,p=line;j<13 && p;j++){ + for(j=0,p=line;j<14 && p;j++){ split[j]=p; p=strchr(p,','); if(p) *p++=0; } if(j<13) continue; - //i=atoi(split[0]); + if (j == 14) { + f=1; // MinJobLvl has been added + m++; + } s_class = pc_calc_base_job(atoi(split[0])); i = s_class.job; u = s_class.upper; @@ -7045,16 +7040,11 @@ int pc_readdb(void) continue; skill_tree[u][i][j].id=atoi(split[1]); skill_tree[u][i][j].max=atoi(split[2]); - - //not required - Celest - //skill_tree[2][i][j].id=atoi(split[1]); //養子職は良く分からないので暫定 - //skill_tree[2][i][j].max=atoi(split[2]); //養子職は良く分からないので暫定 + if (f) skill_tree[u][i][j].joblv=atoi(split[3]); for(k=0;k<5;k++){ - skill_tree[u][i][j].need[k].id=atoi(split[k*2+3]); - skill_tree[u][i][j].need[k].lv=atoi(split[k*2+4]); - //skill_tree[2][i][j].need[k].id=atoi(split[k*2+3]); //養子職は良く分からないので暫定 - //skill_tree[2][i][j].need[k].lv=atoi(split[k*2+4]); //養子職は良く分からないので暫定 + skill_tree[u][i][j].need[k].id=atoi(split[k*2+m]); + skill_tree[u][i][j].need[k].lv=atoi(split[k*2+m+1]); } } fclose(fp); diff --git a/src/map/pc.h b/src/map/pc.h index f7fd924fd..d3a298427 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -185,6 +185,7 @@ int pc_calc_upper(int b_class); struct skill_tree_entry { short id; unsigned char max; + unsigned char joblv; struct { short id; unsigned char lv; diff --git a/src/map/pet.c b/src/map/pet.c index b4dddc372..c48f92970 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -596,14 +596,14 @@ int pet_remove_map(struct map_session_data *sd) struct pet_data *pd=sd->pd; // [Valaris] if(pd->skillbonustimer!=-1) pd->skillbonustimer=-1; - if(pd->skillbonusduration!=-1) pd->skillbonusduration=-1; - if(pd->skilltype !=-1) pd->skilltype=-1; - if(pd->skillval !=-1) pd->skillval=-1; + pd->skilltype=0; + pd->skillval=0; if(pd->skilltimer!=-1) pd->skilltimer=-1; - if(pd->skillduration!=-1) pd->skillduration=-1; - if(pd->skillbonustype!=-1) pd->skillbonustype=-1; - if(pd->skillbonusval!=-1) pd->skillbonusval=-1; - if(sd->perfect_hiding==1) sd->perfect_hiding=0; // end additions + pd->state.skillbonus=-1; + pd->skillduration=0; + pd->skillbonustype=0; + pd->skillbonusval=0; + if(sd->perfect_hiding==1) sd->perfect_hiding=0; // end additions pet_changestate(sd->pd,MS_IDLE,0); if(sd->pet_hungry_timer != -1) @@ -737,9 +737,13 @@ int pet_data_init(struct map_session_data *sd) pd->move_fail_count = 0; pd->next_walktime = pd->attackabletime = pd->last_thinktime = gettick(); pd->msd = sd; - + map_addiddb(&pd->bl); + // initialise + pd->state.skillbonus = -1; + run_script(pet_db[i].script,0,sd->bl.id,0); + if(sd->pet_hungry_timer != -1) pet_hungry_timer_delete(sd); if(battle_config.pet_hungry_delay_rate != 100) @@ -1407,29 +1411,13 @@ int pet_delay_item_drop2(int tid,unsigned int tick,int id,int data) * pet bonus giving skills [Valaris] *------------------------------------------ */ - -int pet_skill_bonus(struct map_session_data *sd,struct pet_data *pd,int type,int val,int duration,int timer,int data) -{ - if(pd==NULL || sd==NULL) - return 1; - - pd->skillbonustype=type; - pd->skillbonusval=val; - pd->skillduration=duration; - pd->skilltimer=timer; - - pd->skillbonustimer=add_timer(gettick()+pd->skilltimer*1000,pet_skill_bonus_timer,sd->bl.id,0); - - return 0; - -} - int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data) { - struct map_session_data *sd=(struct map_session_data*)map_id2bl(id); + struct map_session_data *sd=map_id2sd(id); struct pet_data *pd; + int timer = 0; - if(sd==NULL || sd->bl.type!=BL_PC) + if(sd==NULL) return 1; pd=sd->pd; @@ -1440,38 +1428,26 @@ int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data) if(pd->skillbonustimer != tid) return 0; - pd->skillbonustimer=-1; - - pc_bonus(sd,pd->skillbonustype,pd->skillbonusval); - if(pd->skillbonustype < 56) clif_updatestatus(sd,pd->skillbonustype); - pd->skillbonusduration=add_timer(gettick()+pd->skillduration*1000,pet_skill_bonus_duration,sd->bl.id,0); - - return 0; -} - -int pet_skill_bonus_duration(int tid,unsigned int tick,int id,int data) -{ - struct map_session_data *sd=(struct map_session_data*)map_id2bl(id); - struct pet_data *pd; - - if(sd==NULL || sd->bl.type!=BL_PC) - return 1; - - pd=sd->pd; - - if(pd==NULL || pd->bl.type!=BL_PET) - return 1; - - if(pd->skillbonusduration != tid) - return 0; - - pd->skillbonusduration=-1; + // determine the time for the next timer + if (pd->state.skillbonus == 0) { + // pet bonuses are not active at the moment, so, + pd->state.skillbonus = 1; + timer = pd->skillduration; // the duration for pet bonuses to be in effect + } else if (pd->state.skillbonus == 1) { + // pet bonuses are already active, so, + pd->state.skillbonus = 0; + timer = pd->skilltimer; // the duration which pet bonuses will be reactivated again + } - pc_bonus(sd,pd->skillbonustype,-pd->skillbonusval); - if(pd->skillbonustype < 56) clif_updatestatus(sd,pd->skillbonustype); + if (pd->state.skillbonus == 1 && sd->petDB) + run_script(sd->petDB->script,0,sd->bl.id,0); - pet_skill_bonus(sd,pd,pd->skillbonustype,pd->skillbonusval,pd->skillduration,pd->skilltimer,0); + // add/remove our bonuses, which will be handled by sd->petbonus[] + status_calc_pc(sd, 0); + // wait for the next timer + if (timer) pd->skillbonustimer=add_timer(gettick()+timer,pet_skill_bonus_timer,sd->bl.id,0); + return 0; } @@ -1693,7 +1669,6 @@ int do_init_pet(void) add_timer_func_list(pet_hungry,"pet_hungry"); add_timer_func_list(pet_ai_hard,"pet_ai_hard"); add_timer_func_list(pet_skill_bonus_timer,"pet_skill_bonus_timer"); // [Valaris] - add_timer_func_list(pet_skill_bonus_duration,"pet_skill_bonus_duration"); // [Valaris] add_timer_func_list(pet_recovery_timer,"pet_recovery_timer"); // [Valaris] add_timer_func_list(pet_mag_timer,"pet_mag_timer"); // [Valaris] add_timer_func_list(pet_heal_timer,"pet_heal_timer"); // [Valaris] diff --git a/src/map/pet.h b/src/map/pet.h index 425bc6887..6f532b140 100644 --- a/src/map/pet.h +++ b/src/map/pet.h @@ -55,9 +55,7 @@ int pet_food(struct map_session_data *sd); int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd); int pet_delay_item_drop2(int tid,unsigned int tick,int id,int data); int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap); -int pet_skill_bonus(struct map_session_data *sd,struct pet_data *pd,int type,int val,int duration,int timer,int data); int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data); // [Valaris] -int pet_skill_bonus_duration(int tid,unsigned int tick,int id,int data); // [Valaris] int pet_recovery_timer(int tid,unsigned int tick,int id,int data); // [Valaris] int pet_mag_timer(int tid,unsigned int tick,int id,int data); // [Valaris] int pet_heal_timer(int tid,unsigned int tick,int id,int data); // [Valaris] diff --git a/src/map/script.c b/src/map/script.c index c9f0b8bd5..92ecd8690 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -5713,10 +5713,17 @@ int buildin_petskillbonus(struct script_state *st) duration=conv_num(st,& (st->stack->stack_data[st->start+4])); timer=conv_num(st,& (st->stack->stack_data[st->start+5])); - pd->skillbonusduration=-1; - pd->skillbonustimer=-1; + // initialise bonuses + pd->skillbonustype=type; + pd->skillbonusval=val; + pd->skillduration=duration*1000; + pd->skilltimer=timer*1000; - pet_skill_bonus(sd,pd,type,val,duration,timer,0); + if (pd->state.skillbonus == -1) + pd->state.skillbonus=0; // waiting state + + // wait for timer to start + pd->skillbonustimer=add_timer(gettick()+pd->skilltimer,pet_skill_bonus_timer,sd->bl.id,0); return 0; } diff --git a/src/map/skill.c b/src/map/skill.c index 03704839f..1eb09a8b7 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -4239,6 +4239,12 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int struct skill_unit *su=NULL; if((bl->type==BL_SKILL) && (su=(struct skill_unit *)bl) && (su->group) ){ switch(su->group->unit_id){ + case 0x91: // ankle snare + if (su->group->val2 != 0) + // if it is already trapping something don't spring it, + // remove trap should be used instead + break; + // otherwise fallthrough to below case 0x8f: /* ブラストマイン */ case 0x90: /* スキッドトラップ */ case 0x93: /* ランドマイン */ @@ -4490,7 +4496,9 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int int j = 0; struct guild *g = NULL; // Only usable during WoE - if (!agit_flag) { + if (!agit_flag || + (sd && map[sd->bl.m].flag.nowarpto && // if not allowed to warp to the map + guild_mapname2gc(sd->mapname) == NULL)) { // and it's not a castle... clif_skill_fail(sd,skillid,0,0); map_freeblock_unlock(); return 0; @@ -4500,8 +4508,10 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int strcmp(sd->status.name,g->master)==0) { for(i = 0; i < g->max_member; i++, j++) { if (j>8) j=0; - if ((dstsd = g->member[i].sd) != NULL && sd != dstsd && - !map[sd->bl.m].flag.nowarpto && !map[dstsd->bl.m].flag.nowarp) { + if ((dstsd = g->member[i].sd) != NULL && sd != dstsd) { + if (map[dstsd->bl.m].flag.nowarp && + guild_mapname2gc(sd->mapname) == NULL) + continue; clif_skill_nodamage(src,bl,skillid,skilllv,1); if(map_getcell(sd->bl.m,sd->bl.x+dx[j],sd->bl.y+dy[j],CELL_CHKNOPASS)) dx[j] = dy[j] = 0; @@ -6325,7 +6335,7 @@ int skill_unit_onlimit(struct skill_unit *src,unsigned int tick) { struct map_session_data *sd = NULL; struct map_session_data *p_sd = NULL; - if((sd = (struct map_session_data *)(map_id2bl(sg->src_id))) == NULL) + if((sd = map_id2sd(sg->src_id)) == NULL) return 0; if((p_sd = pc_get_partner(sd)) == NULL) return 0; diff --git a/src/map/status.c b/src/map/status.c index 05c6c8baa..7b2edb38d 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -571,8 +571,11 @@ int status_calc_pc(struct map_session_data* sd,int first) if(sd->status.pet_id > 0) { struct pet_data *pd=sd->pd; if((pd && battle_config.pet_status_support==1) && (battle_config.pet_equip_required==0 || (battle_config.pet_equip_required && pd->equip > 0))) { - if(sd->status.pet_id > 0 && sd->petDB && sd->pet.intimate > 0) - run_script(sd->petDB->script,0,sd->bl.id,0); + if(sd->status.pet_id > 0 && sd->petDB && sd->pet.intimate > 0 && + pd->state.skillbonus == 1) { + pc_bonus(sd,pd->skillbonustype,pd->skillbonusval); +// run_script(sd->petDB->script,0,sd->bl.id,0); + } pele = sd->atk_ele; pdef_ele = sd->def_ele; sd->atk_ele = sd->def_ele = 0; @@ -2832,6 +2835,16 @@ int status_get_race2(struct block_list *bl) else return 0; } +int status_isdead(struct block_list *bl) +{ + nullpo_retr(0, bl); + if(bl->type == BL_MOB && (struct mob_data *)bl) + return ((struct mob_data *)bl)->state.state == MS_DEAD; + else if(bl->type==BL_PC && (struct map_session_data *)bl) + return pc_isdead((struct map_session_data *)bl); + else + return 0; +} // StatusChange系の所得 struct status_change *status_get_sc_data(struct block_list *bl) @@ -2971,6 +2984,9 @@ int status_change_start(struct block_list *bl,int type,int val1,int val2,int val nullpo_retr(0, bl); if(bl->type == BL_SKILL) return 0; + if(bl->type == BL_MOB) + if (status_isdead(bl)) return 0; + nullpo_retr(0, sc_data=status_get_sc_data(bl)); nullpo_retr(0, sc_count=status_get_sc_count(bl)); nullpo_retr(0, option=status_get_option(bl)); @@ -3025,7 +3041,7 @@ int status_change_start(struct block_list *bl,int type,int val1,int val2,int val } } } - else if(bl->type == BL_MOB) { + else if(bl->type == BL_MOB) { } else { if(battle_config.error_log) diff --git a/src/map/status.h b/src/map/status.h index 9bda514b7..672bfc0da 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -256,6 +256,8 @@ int status_get_atk_(struct block_list *bl); int status_get_atk_2(struct block_list *bl); int status_get_atk2(struct block_list *bl); +int status_isdead(struct block_list *bl); + int status_get_sc_def(struct block_list *bl, int type); #define status_get_sc_def_mdef(bl) (status_get_sc_def(bl, SP_MDEF1)) #define status_get_sc_def_vit(bl) (status_get_sc_def(bl, SP_DEF2)) -- cgit v1.2.3-60-g2f50