diff options
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/atcommand.c | 8 | ||||
-rw-r--r-- | src/map/battle.c | 11 | ||||
-rw-r--r-- | src/map/battle.h | 2 | ||||
-rw-r--r-- | src/map/clif.c | 32 | ||||
-rw-r--r-- | src/map/clif.h | 1 | ||||
-rw-r--r-- | src/map/itemdb.c | 2 | ||||
-rw-r--r-- | src/map/script.c | 218 | ||||
-rw-r--r-- | src/map/skill.c | 17 | ||||
-rw-r--r-- | src/map/status.c | 16 | ||||
-rw-r--r-- | src/map/status.h | 32 |
10 files changed, 296 insertions, 43 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 10c96e317..cc29fa1bb 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -4713,7 +4713,13 @@ ACMD(disguise) clif->message(fd, msg_txt(1144)); // Character cannot be disguised while mounted. return false; } - + + if(sd->sc.data[SC_MONSTER_TRANSFORM]) + { + clif->message(fd, msg_txt(1488)); // Character cannot be disguised while in monster form. + return false; + } + pc->disguise(sd, id); clif->message(fd, msg_txt(122)); // Disguise applied. diff --git a/src/map/battle.c b/src/map/battle.c index ef62eb1d2..fb950860e 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -944,11 +944,13 @@ int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct block_ break; } } +#ifndef RENEWAL //It was discovered that ranged defense also counts vs magic! [Skotlex] if ( wflag&BF_SHORT ) cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; else cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; +#endif cardfix = cardfix * ( 100 - tsd->bonus.magic_def_rate ) / 100; @@ -4534,6 +4536,8 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list ATK_ADDRATE(sd->bonus.atk_rate); if(flag.cri && sd->bonus.crit_atk_rate) ATK_ADDRATE(sd->bonus.crit_atk_rate); + if(flag.cri && sc && sc->data[SC_MTF_CRIDAMAGE]) + ATK_ADDRATE(25);// temporary it should be 'bonus.crit_atk_rate' #ifndef RENEWAL if(sd->status.party_id && (temp=pc->checkskill(sd,TK_POWER)) > 0){ @@ -4721,6 +4725,8 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list #ifdef RENEWAL if( wd.flag&BF_LONG ) ATK_ADDRATE(sd->bonus.long_attack_atk_rate); + if( sc && sc->data[SC_MTF_RANGEATK] ) + ATK_ADDRATE(25);// temporary it should be 'bonus.long_attack_atk_rate' #endif if( (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) @@ -5472,6 +5478,9 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t return ATK_DEF; return ATK_MISS; } + if( tsc && tsc->data[SC_MTF_MLEATKED] && rnd()%100 < 20 ) + clif->skill_nodamage(target, target, SM_ENDURE, 5, + sc_start(target, SC_ENDURE, 100, 5, skill->get_time(SM_ENDURE, 5))); } if(tsc && tsc->data[SC_KAAHI] && tsc->data[SC_KAAHI]->val4 == INVALID_TIMER && tstatus->hp < tstatus->max_hp) @@ -6477,7 +6486,7 @@ static const struct _battle_data { { "feature.banking", &battle_config.feature_banking, 1, 0, 1, }, { "feature.auction", &battle_config.feature_auction, 0, 0, 2, }, - + { "mon_trans_disable_in_gvg", &battle_config.mon_trans_disable_in_gvg, 0, 0, 1, }, }; #ifndef STATS_OPT_OUT /** diff --git a/src/map/battle.h b/src/map/battle.h index 533fa40b0..1aa07b2be 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -463,6 +463,8 @@ struct Battle_Config { int feature_banking; int feature_auction; + + int mon_trans_disable_in_gvg; } battle_config; // Dammage delayed info diff --git a/src/map/clif.c b/src/map/clif.c index 823a44956..060509807 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -9600,6 +9600,11 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { if (sd->sc.opt2) //Client loses these on warp. clif->changeoption(&sd->bl); + if( battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m) ){ + status_change_end(&sd->bl, SC_MONSTER_TRANSFORM, INVALID_TIMER); + clif->message(sd->fd, msg_txt(1488)); // Transforming into monster is not allowed in Guild Wars. + } + clif->weather_check(sd); // For automatic triggering of NPCs after map loading (so you don't need to walk 1 step first) @@ -9617,7 +9622,6 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { clif->clearunit_area(&sd->bl, CLR_DEAD); else { skill->usave_trigger(sd); - clif->changed_dir(&sd->bl, SELF); } // Trigger skill effects if you appear standing on them @@ -17451,7 +17455,8 @@ void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) { if( result != CSBR_SUCCESS ) pc->getcash(sd, clif->cs.data[tab][j]->price * get_count,0); - } + } else /* create_egg succeeded so mark as success */ + result = CSBR_SUCCESS; } } } else { @@ -17536,6 +17541,28 @@ void clif_partytickack(struct map_session_data* sd, bool flag) { WFIFOSET(sd->fd, packet_len(0x2c9)); } +void clif_ShowScript(struct block_list* bl, const char* message) { + char buf[256]; + int len; + nullpo_retv(bl); + + if(!message) + return; + + len = strlen(message)+1; + + if( len > sizeof(buf)-8 ) { + ShowWarning("clif_ShowScript: Truncating too long message '%s' (len=%d).\n", message, len); + len = sizeof(buf)-8; + } + + WBUFW(buf,0)=0x8b3; + WBUFW(buf,2)=len+8; + WBUFL(buf,4)=bl->id; + safestrncpy((char *) WBUFP(buf,8),message,len); + clif->send((unsigned char *) buf,WBUFW(buf,2),bl,ALL_CLIENT); +} + void clif_status_change_end(struct block_list *bl, int tid, enum send_target target, int type) { struct packet_status_change_end p; @@ -18390,6 +18417,7 @@ void clif_defaults(void) { clif->wisexin = clif_wisexin; clif->wisall = clif_wisall; clif->PMIgnoreList = clif_PMIgnoreList; + clif->ShowScript = clif_ShowScript; /* trade handling */ clif->traderequest = clif_traderequest; clif->tradestart = clif_tradestart; diff --git a/src/map/clif.h b/src/map/clif.h index 2baca2aaf..6d0fc0fc1 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -759,6 +759,7 @@ struct clif_interface { void (*wisexin) (struct map_session_data *sd,int type,int flag); void (*wisall) (struct map_session_data *sd,int type,int flag); void (*PMIgnoreList) (struct map_session_data* sd); + void (*ShowScript) (struct block_list* bl, const char* message); /* trade handling */ void (*traderequest) (struct map_session_data* sd, const char* name); void (*tradestart) (struct map_session_data* sd, uint8 type); diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 09eec557d..5c698b3c9 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -1946,7 +1946,7 @@ void itemdb_read(void) { sv->readdb(map->db_path, "item_avail.txt", ',', 2, 2, -1, itemdb->read_itemavail); sv->readdb(map->db_path, DBPATH"item_trade.txt", ',', 3, 3, -1, itemdb->read_itemtrade); - sv->readdb(map->db_path, "item_delay.txt", ',', 2, 2, -1, itemdb->read_itemdelay); + sv->readdb(map->db_path, DBPATH"item_delay.txt", ',', 2, 2, -1, itemdb->read_itemdelay); sv->readdb(map->db_path, "item_stack.txt", ',', 3, 3, -1, itemdb->read_stack); sv->readdb(map->db_path, DBPATH"item_buyingstore.txt", ',', 1, 1, -1, itemdb->read_buyingstore); sv->readdb(map->db_path, "item_nouse.txt", ',', 3, 3, -1, itemdb->read_nouse); diff --git a/src/map/script.c b/src/map/script.c index 1bedb78b6..c74eff07b 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -610,16 +610,16 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) { const char *p2; char *arg = NULL; + char null_arg = '\0'; int func; func = script->add_word(p); if( script->str_data[func].type == C_FUNC ){ - char argT = 0; // buildin function script->addl(func); script->addc(C_ARG); arg = script->buildin[script->str_data[func].val]; - if( !arg ) arg = &argT; + if( !arg ) arg = &null_arg; // Use a dummy, null string } else if( script->str_data[func].type == C_USERFUNC || script->str_data[func].type == C_USERFUNC_POS ){ // script defined function script->addl(script->buildin_callsub_ref); @@ -14340,32 +14340,112 @@ BUILDIN(setitemscript) return true; } -/* Work In Progress [Lupus] - BUILDIN(addmonsterdrop) - { - int class_,item_id,chance; - class_=script_getnum(st,2); - item_id=script_getnum(st,3); - chance=script_getnum(st,4); - if(class_>1000 && item_id>500 && chance>0) { - script_pushint(st,1); - } else { - script_pushint(st,0); - } - } - - BUILDIN(delmonsterdrop) - { - int class_,item_id; - class_=script_getnum(st,2); - item_id=script_getnum(st,3); - if(class_>1000 && item_id>500) { - script_pushint(st,1); - } else { - script_pushint(st,0); - } - } - */ +/*======================================================= + * Temporarily add or update a mob drop + * Original Idea By: [Lupus], [Akinari] + * + * addmonsterdrop <mob_id or name>,<item_id>,<rate>; + * + * If given an item the mob already drops, the rate + * is updated to the new rate. Rate must be in the range [1:10000] + * Returns 1 if succeeded (added/updated a mob drop) + *-------------------------------------------------------*/ +BUILDIN(addmonsterdrop) { + struct mob_db *monster; + int item_id, rate, i, c = MAX_MOB_DROP; + + if( script_isstring(st,2) ) + monster = mob->db(mob->db_searchname(script_getstr(st,2))); + else + monster = mob->db(script_getnum(st,2)); + + if( monster == mob->dummy ) { + if( script_isstring(st,2) ) { + ShowError("buildin_addmonsterdrop: invalid mob name: '%s'.\n", script_getstr(st,2)); + } else { + ShowError("buildin_addmonsterdrop: invalid mob id: '%d'.\n", script_getnum(st,2)); + } + return false; + } + + item_id = script_getnum(st,3); + if( !itemdb->exists(item_id) ) { + ShowError("buildin_addmonsterdrop: Invalid item ID: '%d'.\n", item_id); + return false; + } + + rate = script_getnum(st,4); + if( rate < 1 || rate > 10000 ) { + ShowWarning("buildin_addmonsterdrop: Invalid drop rate '%d'. Capping to the [1:10000] range.\n", rate); + rate = cap_value(rate,1,10000); + } + + for( i = 0; i < MAX_MOB_DROP; i++ ) { + if( monster->dropitem[i].nameid == item_id ) // Item ID found + break; + if( c == MAX_MOB_DROP && monster->dropitem[i].nameid < 1 ) // First empty slot + c = i; + } + if( i < MAX_MOB_DROP ) // If the item ID was found, prefer it + c = i; + + if( c < MAX_MOB_DROP ) { + // Fill in the slot with the item and rate + monster->dropitem[c].nameid = item_id; + monster->dropitem[c].p = rate; + script_pushint(st,1); + } else { + //No place to put the new drop + script_pushint(st,0); + } + + return true; +} + +/*======================================================= + * Temporarily remove a mob drop + * Original Idea By: [Lupus], [Akinari] + * + * delmonsterdrop <mob_id or name>,<item_id>; + * + * Returns 1 if succeeded (deleted a mob drop) + *-------------------------------------------------------*/ +BUILDIN(delmonsterdrop) { + struct mob_db *monster; + int item_id, i; + + if( script_isstring(st,2) ) + monster = mob->db(mob->db_searchname(script_getstr(st,2))); + else + monster = mob->db(script_getnum(st,2)); + + if( monster == mob->dummy ) { + if( script_isstring(st,2) ) { + ShowError("buildin_delmonsterdrop: invalid mob name: '%s'.\n", script_getstr(st,2)); + } else { + ShowError("buildin_delmonsterdrop: invalid mob id: '%d'.\n", script_getnum(st,2)); + } + return false; + } + + item_id = script_getnum(st,3); + if( !itemdb->exists(item_id) ) { + ShowError("buildin_delmonsterdrop: Invalid item ID: '%d'.\n", item_id); + return false; + } + + for( i = 0; i < MAX_MOB_DROP; i++ ) { + if( monster->dropitem[i].nameid == item_id ) { + monster->dropitem[i].nameid = 0; + monster->dropitem[i].p = 0; + script_pushint(st,1); + return true; + } + } + // No drop on that monster + script_pushint(st,0); + return true; +} /*========================================== * Returns some values of a monster [Lupus] @@ -16858,6 +16938,84 @@ BUILDIN(npcskill) { return true; } + +/* Turns a player into a monster and grants SC attribute effect. [malufett/Hercules] + * montransform <monster name/id>, <duration>, <sc type>, <val1>, <val2>, <val3>, <val4>; */ +BUILDIN(montransform) { + int tick; + enum sc_type type; + struct block_list* bl; + char msg[CHAT_SIZE_MAX]; + int mob_id, val1, val2, val3, val4; + + if( (bl = map->id2bl(st->rid)) == NULL ) + return true; + + if( script_isstring(st, 2) ) + mob_id = mob->db_searchname(script_getstr(st, 2)); + else{ + mob_id = mob->db_checkid(script_getnum(st, 2)); + } + + tick = script_getnum(st, 3); + type = (sc_type)script_getnum(st, 4); + val1 = val2 = val3 = val4 = 0; + + if( mob_id == 0 ) { + if( script_isstring(st,2) ) + ShowWarning("buildin_montransform: Attempted to use non-existing monster '%s'.\n", script_getstr(st, 2)); + else + ShowWarning("buildin_montransform: Attempted to use non-existing monster of ID '%d'.\n", script_getnum(st, 2)); + return false; + } + + if(mob_id == MOBID_EMPERIUM) { + ShowWarning("buildin_montransform: Monster 'Emperium' cannot be used.\n"); + return false; + } + + if( !(type > SC_NONE && type < SC_MAX) ){ + ShowWarning("buildin_montransform: Unsupported status change id %d\n", type); + return false; + } + + if (script_hasdata(st, 5)) + val1 = script_getnum(st, 5); + + if (script_hasdata(st, 6)) + val2 = script_getnum(st, 6); + + if (script_hasdata(st, 7)) + val3 = script_getnum(st, 7); + + if (script_hasdata(st, 8)) + val4 = script_getnum(st, 8); + + if( tick != 0 ){ + struct map_session_data *sd = map->id2sd(bl->id); + struct mob_db *monster = mob->db(mob_id); + + if( !sd ) return true; + + if( battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m) ){ + clif->message(sd->fd, msg_txt(1488)); // Transforming into monster is not allowed in Guild Wars. + return true; + } + + if( sd->disguise != -1 ){ + clif->message(sd->fd, msg_txt(1486)); // Cannot transform into monster while in disguise. + return true; + } + + sprintf(msg, msg_txt(1485), monster->name); // Traaaansformation-!! %s form!! + clif->ShowScript(&sd->bl, msg); + status_change_end(bl, SC_MONSTER_TRANSFORM, INVALID_TIMER); // Clear previous + sc_start2(bl, SC_MONSTER_TRANSFORM, 100, mob_id, type, tick); + sc_start4(bl, type, 100, val1, val2, val3, val4, tick); + } + return true; +} + struct hQueue *script_hqueue_get(int idx) { if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) return NULL; @@ -17669,6 +17827,8 @@ void script_parse_builtin(void) { BUILDIN_DEF(disguise,"i"), //disguise player. Lupus BUILDIN_DEF(undisguise,""), //undisguise player. Lupus BUILDIN_DEF(getmonsterinfo,"ii"), //Lupus + BUILDIN_DEF(addmonsterdrop,"vii"), + BUILDIN_DEF(delmonsterdrop,"vi"), BUILDIN_DEF(axtoi,"s"), BUILDIN_DEF(query_sql,"s*"), BUILDIN_DEF(query_logsql,"s*"), @@ -17818,6 +17978,8 @@ void script_parse_builtin(void) { BUILDIN_DEF(sit, "?"), BUILDIN_DEF(stand, "?"), BUILDIN_DEF(issit, "?"), + + BUILDIN_DEF(montransform, "vii????"), // Monster Transform [malufett/Hercules] /* New BG Commands [Hercules] */ BUILDIN_DEF(bg_create_team,"sii"), diff --git a/src/map/skill.c b/src/map/skill.c index aed01b1f7..4daf3f753 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1356,7 +1356,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 src = sd?&sd->bl:src; } - if( attack_type&BF_WEAPON ) { + if( attack_type&BF_WEAPON && skill_id != CR_REFLECTSHIELD ) { // Coma, Breaking Equipment if( sd && sd->special_state.bonus_coma ) { rate = sd->weapon_coma_ele[tstatus->def_ele]; @@ -6570,7 +6570,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case SA_DISPELL: if (flag&1 || (i = skill->get_splash(skill_id, skill_lv)) < 1) - { + { + if( sd && dstsd && !map_flag_vs(sd->bl.m) + && (sd->status.party_id == 0 || sd->status.party_id != dstsd->status.party_id) ) { + // Outside PvP it should only affect party members and no skill fail message. + break; + } clif->skill_nodamage(src,bl,skill_id,skill_lv,1); if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_ROGUE) //Rogue's spirit defends againt dispel. @@ -6582,14 +6587,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } if(status->isimmune(bl) || !tsc || !tsc->count) break; - - if( sd && dstsd && !map_flag_vs(sd->bl.m) - && (sd->status.party_id == 0 || sd->status.party_id != dstsd->status.party_id) ) { - // Outside PvP it should only affect party members - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - for(i = 0; i < SC_MAX; i++) { if ( !tsc->data[i] ) continue; diff --git a/src/map/status.c b/src/map/status.c index ae900e04d..8a2ac7cd6 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -991,6 +991,9 @@ void initChangeTables(void) { status->ChangeFlagTable[SC_ALL_RIDING] = SCB_SPEED; status->ChangeFlagTable[SC_WEDDING] = SCB_SPEED; + status->ChangeFlagTable[SC_MTF_ASPD] = SCB_ASPD|SCB_HIT; + status->ChangeFlagTable[SC_MTF_MATK] = SCB_MATK; + status->ChangeFlagTable[SC_MTF_MLEATKED] |= SCB_ALL; /* status->DisplayType Table [Ind/Hercules] */ status->DisplayType[SC_ALL_RIDING] = true; @@ -3083,6 +3086,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { sd->subele[ELE_EARTH] += i; sd->subele[ELE_FIRE] -= i; } + if( sc->data[SC_MTF_MLEATKED] ) + sd->subele[ELE_NEUTRAL] += 2; if( sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3 ) sd->magic_addele[ELE_FIRE] += 25; if( sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 3 ) @@ -4590,6 +4595,9 @@ unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, matk += matk * sc->data[SC_MOONLIT_SERENADE]->val2/100; if (sc->data[SC_MELODYOFSINK]) matk += matk * sc->data[SC_MELODYOFSINK]->val3/100; + if (sc->data[SC_MTF_MATK]) + matk += matk * 25 / 100; + if (sc->data[SC_BEYOND_OF_WARCRY]) matk -= matk * sc->data[SC_BEYOND_OF_WARCRY]->val3/100; @@ -4639,6 +4647,8 @@ signed short status_calc_hit(struct block_list *bl, struct status_change *sc, in if( !viewable ){ /* some statuses that are hidden in the status window */ + if(sc->data[SC_MTF_ASPD]) + hit += 5; return (short)cap_value(hit,1,SHRT_MAX); } @@ -5342,6 +5352,8 @@ short status_calc_fix_aspd(struct block_list *bl, struct status_change *sc, int aspd -= 50; // +5 ASPD if( sc && sc->data[SC_FIGHTINGSPIRIT] && sc->data[SC_FIGHTINGSPIRIT]->val2 ) aspd -= (bl->type==BL_PC?pc->checkskill((TBL_PC *)bl, RK_RUNEMASTERY):10) / 10 * 40; + if( sc && sc->data[SC_MTF_ASPD] ) + aspd -= 10; return cap_value(aspd, 0, 2000); // will be recap for proper bl anyway } @@ -9631,6 +9643,10 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_FULL_THROTTLE: sc_start(bl,SC_REBOUND,100,sce->val1,skill->get_time2(ALL_FULL_THROTTLE,sce->val1)); break; + case SC_MONSTER_TRANSFORM: + if( sce->val2 ) + status_change_end(bl, (sc_type)sce->val2, INVALID_TIMER); + break; case SC_ITEMSCRIPT: if( sd ) { switch( sce->val1 ) { diff --git a/src/map/status.h b/src/map/status.h index c7518a213..9b1721d1a 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -671,6 +671,12 @@ typedef enum sc_type { SC_ANGEL_PROTECT, SC_ILLUSIONDOPING, + SC_MTF_ASPD, + SC_MTF_RANGEATK, + SC_MTF_MATK, + SC_MTF_MLEATKED, + SC_MTF_CRIDAMAGE, + SC_MAX, //Automatically updated max, used in for's to check we are within bounds. } sc_type; // Official status change ids, used to display status icons on the client. @@ -1405,6 +1411,32 @@ enum si_type { //SI_ = 735, SI_CHILL = 736, SI_BURNT = 737, + SI_B_TRAP = 752, + SI_E_CHAIN = 753, + SI_E_QD_SHOT_READY = 754, + SI_C_MARKER = 755, + SI_H_MINE = 756, + SI_H_MINE_SPLASH = 757, + SI_P_ALTER = 758, + SI_HEAT_BARREL = 759, + SI_ANTI_M_BLAST = 760, + SI_SLUGSHOT = 761, + SI_SWORDCLAN = 762, + SI_ARCWANDCLAN = 763, + SI_GOLDENMACECLAN = 764, + SI_CROSSBOWCLAN = 765, + SI_PACKING_ENVELOPE1 = 766, + SI_PACKING_ENVELOPE2 = 767, + SI_PACKING_ENVELOPE3 = 768, + SI_PACKING_ENVELOPE4 = 769, + SI_PACKING_ENVELOPE5 = 770, + SI_PACKING_ENVELOPE6 = 771, + SI_PACKING_ENVELOPE7 = 772, + SI_PACKING_ENVELOPE8 = 773, + SI_PACKING_ENVELOPE9 = 774, + SI_PACKING_ENVELOPE10 = 775, + SI_GLASTHEIM_TRANS = 776, + SI_HEAT_BARREL_AFTER = 778, SI_MAX, }; // JOINTBEAT stackable ailments |