About This File
Good day! I've been an observer since the beginning of time and I want to share this script hoping that it will help fellow human beings who need it. This was a paid script of mine and I hired @sader1992 to help me finish it in 2020. I'm hoping someone will improve the code in the near future with other stuff to give another flavor for Endless Tower. This works with the latest version of rAthena.
Requirement: Y'all need this patch for +damage to work setunitdata script command monster stat recaulculation fixes #3968
About the script:
It is simply Endless Tower with Easy, Veteran, Nightmare, Hell & Torment Difficulties. You can edit the values I pre-assigned:
.@bonus_hp_rate += 0; // The zero / "0" is calculated in %
.@bonus_dmg_rate += 0;
.@bonus_damagetaken += 0;
.@bonus_hit += 0;
.@bonus_str += 0;
.@bonus_agi += 0;
.@bonus_vit += 0;
.@bonus_int += 0;
.@bonus_dex += 0;
.@bonus_luk += 0;
This part is for the difficulty settings and adding stats to the monsters:
// Difficulty Function
//============================================================
function script F_Tower_Monster_Summon {
.@map$ = getarg(0, "");
.@x1 = getarg(1, 0);
.@y1 = getarg(2, 0);
.@x2 = getarg(3, 0);
.@y2 = getarg(4, 0);
.@mob_name$ = getarg(5, 0);
.@mob_id = getarg(6, 0);
.@amount = getarg(7, 0);
.@label$ = getarg(8, "");
switch('level_mode){
case 1://Easy
.@bonus_hp_rate += 0;
.@bonus_dmg_rate += 0;
.@bonus_damagetaken += 0;
.@bonus_hit += 0;
.@bonus_str += 0;
.@bonus_agi += 0;
.@bonus_vit += 0;
.@bonus_int += 0;
.@bonus_dex += 0;
.@bonus_luk += 0;
break;
case 2://Veteran
.@bonus_hp_rate += 100;
.@bonus_dmg_rate += 100;
.@bonus_damagetaken += -10;
.@bonus_hit += 100;
.@bonus_str += 100;
.@bonus_agi += 100;
.@bonus_vit += 100;
.@bonus_int += 100;
.@bonus_dex += 100;
.@bonus_luk += 100;
break;
case 3://Nightmare
.@bonus_hp_rate += 250;
.@bonus_dmg_rate += 250;
.@bonus_damagetaken += -20;
.@bonus_hit += 250;
.@bonus_str += 250;
.@bonus_agi += 250;
.@bonus_vit += 250;
.@bonus_int += 250;
.@bonus_dex += 250;
.@bonus_luk += 250;
break;
case 4://Hell
.@bonus_hp_rate += 500;
.@bonus_dmg_rate += 500;
.@bonus_damagetaken += -30;
.@bonus_hit += 500;
.@bonus_str += 500;
.@bonus_agi += 500;
.@bonus_vit += 500;
.@bonus_int += 500;
.@bonus_dex += 500;
.@bonus_luk += 500;
break;
case 5://Torment
.@bonus_hp_rate += 1000;
.@bonus_dmg_rate += 1000;
.@bonus_damagetaken += -40;
.@bonus_hit += 1000;
.@bonus_str += 1000;
.@bonus_agi += 1000;
.@bonus_vit += 1000;
.@bonus_int += 1000;
.@bonus_dex += 1000;
.@bonus_luk += 1000;
break;
}
deletearray $@mobid,getarraysize($@mobid);
areamonster .@map$, .@x1, .@y1, .@x2, .@y2, .@mob_name$, .@mob_id, .@amount, .@label$;
copyarray .@GID, $@mobid, getarraysize($@mobid);
if(!.@bonus_hp_rate&& !.@bonus_dmg_rate&& !.@bonus_damagetaken&& !.@bonus_hit&& !.@bonus_str&& !.@bonus_agi&& !.@bonus_vit&& !.@bonus_int&& !.@bonus_dex&& !.@bonus_luk)
return;
getunitdata .@GID, .@ST;
if(.@bonus_hp_rate){
.@HP = .@ST[UMOB_MAXHP] + ((.@ST[UMOB_MAXHP] * .@bonus_hp_rate ) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_MAXHP, .@HP);
setunitdata(.@GID[.@i], UMOB_HP, .@HP);
}
}
if(.@bonus_dmg_rate){
.@ATKMIN = .@ST[UMOB_ATKMIN] + ((.@ST[UMOB_ATKMIN] * .@bonus_dmg_rate) /100);
.@ATKMAX = .@ST[UMOB_ATKMAX] + ((.@ST[UMOB_ATKMAX] * .@bonus_dmg_rate) /100);
.@MATKMIN = .@ST[UMOB_MATKMIN] + ((.@ST[UMOB_MATKMIN] * .@bonus_dmg_rate) /100);
.@MATKMAX = .@ST[UMOB_MATKMAX] + ((.@ST[UMOB_MATKMAX] * .@bonus_dmg_rate) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_ATKMIN, .@ATKMIN);
setunitdata(.@GID[.@i], UMOB_ATKMAX, .@ATKMAX);
setunitdata(.@GID[.@i], UMOB_MATKMIN, .@MATKMIN);
setunitdata(.@GID[.@i], UMOB_MATKMAX, .@MATKMAX);
}
}
if(.@bonus_damagetaken){
.@DAMAGETAKEN = .@ST[UMOB_DAMAGETAKEN] + ((.@ST[UMOB_DAMAGETAKEN] * .@bonus_damagetaken) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_DAMAGETAKEN, .@DAMAGETAKEN);
}
}
if(.@bonus_hit){
.@HIT = .@ST[UMOB_HIT] + ((.@ST[UMOB_HIT] * .@bonus_hit) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_HIT, .@HIT);
}
}
if(.@bonus_str){
.@STR = .@ST[UMOB_STR] + ((.@ST[UMOB_STR] * .@bonus_str) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_STR, .@STR);
}
}
if(.@bonus_agi){
.@AGI = .@ST[UMOB_AGI] + ((.@ST[UMOB_AGI] * .@bonus_agi) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_AGI, .@AGI);
}
}
if(.@bonus_vit){
.@VIT = .@ST[UMOB_VIT] + ((.@ST[UMOB_VIT] * .@bonus_vit) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_VIT, .@VIT);
}
}
if(.@bonus_int){
.@INT = .@ST[UMOB_INT] + ((.@ST[UMOB_INT] * .@bonus_int) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_INT, .@INT);
}
}
if(.@bonus_dex){
.@DEX = .@ST[UMOB_DEX] + ((.@ST[UMOB_DEX]) * .@bonus_dex) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_DEX, .@DEX);
}
}
if(.@bonus_luk){
.@LUK = .@ST[UMOB_LUK] + ((.@ST[UMOB_LUK] * .@bonus_luk) /100);
for(.@i=0;.@i<getarraysize(.@GID);.@i++){
setunitdata(.@GID[.@i], UMOB_LUK, .@LUK);
}
}
return;
}
This part is for the rewards: It gives #INSTANCEPOINTS and EXP depending on the difficulty you're on.
// Reward Function
//============================================================
function script F_Tower_Reward {
setarray .@rewards[1],1,3,6,12,24;
setarray .@modes$[1],"Easy Mode","Veteran Mode","Nightmare Mode","Hell Mode","Torment Mode";
setarray .@bonusExp[1],653047446,672905476,843378037,6160565694,45000661693;
'rewardz = .@rewards['level_mode];
'modez$ = .@modes$['level_mode];
'bonuzExp = .@bonusExp['level_mode];
'party_id = instance_live_info(ILI_OWNER);
getpartymember 'party_id, 1;
getpartymember 'party_id, 2;
'map$ = instance_mapname("6@tower");
copyarray .@CID,$@partymembercid,$@partymembercount;
copyarray .@AID,$@partymemberaid,$@partymembercount;
for(.@i=0;.@i<getarraysize(.@CID);.@i++){
if(isloggedin(.@AID[.@i],.@CID[.@i])){
if(strcharinfo(3,.@CID[.@i]) == 'map$){
set(#INSTANCEPOINTS,(getvar(#INSTANCEPOINTS,.@CID[.@i]) + 'rewardz),.@CID[.@i]);
announce "The party [ "+ getpartyname('party_id) +" ] has defeated Endless Tower on " + 'modez$ + ".",bc_all;
message strcharinfo(0,.@CID[.@i]),"You've been granted " + 'rewardz + " Instance Points.";
message strcharinfo(0,.@CID[.@i]),"You now have " + getvar(#INSTANCEPOINTS,.@CID[.@i]) + " Instance Points";
getexp 'bonuzExp,'bonuzExp,.@CID[.@i];
}
}
}
return;
}
I assigned a monster (1613 : metalling) to show us that the stats boost really works:
//if(unitexists(.@GID)){
// if(.@mob_id == 1613){
// debugmes "BEFORE UMOB_MAXHP " + .@ST[UMOB_MAXHP];
// debugmes "BEFORE UMOB_ATKMIN " + .@ST[UMOB_ATKMIN];
// debugmes "BEFORE UMOB_ATKMAX " + .@ST[UMOB_ATKMAX];
// debugmes "BEFORE UMOB_MATKMIN " + .@ST[UMOB_MATKMIN];
// debugmes "BEFORE UMOB_MATKMAX " + .@ST[UMOB_MATKMAX];
// debugmes "BEFORE UMOB_HIT " + .@ST[UMOB_HIT];
// debugmes "BEFORE UMOB_STR " + .@ST[UMOB_STR];
// debugmes "BEFORE UMOB_AGI " + .@ST[UMOB_AGI];
// debugmes "BEFORE UMOB_VIT " + .@ST[UMOB_VIT];
// debugmes "BEFORE UMOB_INT " + .@ST[UMOB_INT];
// debugmes "BEFORE UMOB_DEX " + .@ST[UMOB_DEX];
// debugmes "BEFORE UMOB_LUK " + .@ST[UMOB_LUK];
// }
// }
//if(unitexists(.@GID)){
// if(.@mob_id == 1613){
// getunitdata .@GID, .@ST2;
// debugmes "AFTER UMOB_MAXHP " + .@ST2[UMOB_MAXHP];
// debugmes "AFTER UMOB_ATKMIN " + .@ST2[UMOB_ATKMIN];
// debugmes "AFTER UMOB_ATKMAX " + .@ST2[UMOB_ATKMAX];
// debugmes "AFTER UMOB_MATKMIN " + .@ST2[UMOB_MATKMIN];
// debugmes "AFTER UMOB_MATKMAX " + .@ST2[UMOB_MATKMAX];
// debugmes "AFTER UMOB_HIT " + .@ST2[UMOB_HIT];
// debugmes "AFTER UMOB_STR " + .@ST2[UMOB_STR];
// debugmes "AFTER UMOB_AGI " + .@ST2[UMOB_AGI];
// debugmes "AFTER UMOB_VIT " + .@ST2[UMOB_VIT];
// debugmes "AFTER UMOB_INT " + .@ST2[UMOB_INT];
// debugmes "AFTER UMOB_DEX " + .@ST2[UMOB_DEX];
// debugmes "AFTER UMOB_LUK " + .@ST2[UMOB_LUK];
// }
//}
PS: I'm also integrating this to other instances. Maybe I'll post it if people requests it.
Edited by Ylen X Walker
What's New in Version 1.2.0 See changelog
Released
Added a function settings for easy access of variables