• 0
Rotciv

Create Ground Skill

Question

Hey!
So I'm having problems with creating a ground skill (like Safety Wall or Fire Pillar). I wanted to create a skill that "puts" an object on the ground (like a BL_SKILL) and use some other object sprite or even a new one. But I don't know where to start since I can't figure out where is specified which sprite the ground skills are using and how should the BL_SKILLs behave, so I need some clues to start... Can anybody help?

 

Thank you for the support

Share this post


Link to post
Share on other sites

17 answers to this question

  • 0

@lllaaazzz Thank you so much! I had no idea where to start. I don't have enough time now, but I will surely test all these functions I see what can be done. Thanks for the help!

Share this post


Link to post
Share on other sites
  • 0
2 minutes ago, Rotciv said:

??

Hold on some disrespectful kid just really pissed me off ill re write it for you

Share this post


Link to post
Share on other sites
  • 0

Okay so ground skills all follow the UNT_UGLYDANCE format or whatever, you can use the same UNT_ a bunch of different ways but the actual effects will be pretty strict unless you get creative with your writing, so you can easily make a bunch of different sized sanctuary/venom dusts and things like that, but they will most likely all have the same effect... unless you get creative right? ok so this is one of my UNT_'s that ive been working on . 

skill.c

case KN_DOMINATOR:
		case NC_NEUTRALBARRIER:
				struct status_change *tsc = status->get_sc(src);
			skill->clear_unitgroup(src); // To remove previous skills - cannot used combined
			if( tsc && tsc->data[SC_STAGETHREE] ) {
				if( (sg = skill->unitsetting(src,NC_NEUTRALBARRIER,3,src->x,src->y,0)) != NULL ) {
				sc_start2(src,src,SC_NEUTRALBARRIER_MASTER,100,skill_lv,sg->group_id,skill->get_time(skill_id,skill_lv));
				status_change_end(src, SC_STAGETHREE, INVALID_TIMER);
				sc_start(src, src,SC_STAGETHREE,100,skill_lv,skill->get_time(skill_id, skill_lv));
				if( sd ) pc->overheat(sd,1);
				}
				break;
			}
			
			if( tsc && tsc->data[SC_STAGETWO] ) {
				if( (sg = skill->unitsetting(src,NC_NEUTRALBARRIER,3,src->x,src->y,0)) != NULL ) {
				sc_start2(src,src,SC_NEUTRALBARRIER_MASTER,100,skill_lv,sg->group_id,skill->get_time(skill_id,skill_lv));
				status_change_end(src, SC_STAGETWO, INVALID_TIMER);
				sc_start(src, src,SC_STAGETHREE,100,skill_lv,skill->get_time(skill_id, skill_lv));
				if( sd ) pc->overheat(sd,1);
				}
				break;
			}
			
			if( tsc && tsc->data[SC_STAGEONE] ) {
				if( (sg = skill->unitsetting(src,NC_NEUTRALBARRIER,2,src->x,src->y,0)) != NULL ) {
				sc_start2(src,src,skill_id == NC_NEUTRALBARRIER ? SC_NEUTRALBARRIER_MASTER : SC_STEALTHFIELD_MASTER,100,skill_lv,sg->group_id,skill->get_time(skill_id,skill_lv));
				status_change_end(src, SC_STAGEONE, INVALID_TIMER);
				sc_start(src, src,SC_STAGETWO,100,skill_lv,skill->get_time(skill_id, skill_lv));
				if( sd ) pc->overheat(sd,1);
				}
				break;
			}
			
			if( (sg = skill->unitsetting(src,NC_NEUTRALBARRIER,1,src->x,src->y,0)) != NULL ) {
				sc_start2(src,src,SC_NEUTRALBARRIER_MASTER,100,skill_lv,sg->group_id,skill->get_time(skill_id,skill_lv));
				sc_start(src, src,SC_STAGEONE,100,skill_lv,skill->get_time(skill_id, skill_lv));
				if( sd ) pc->overheat(sd,1);
			}
			break;

And in my skill.db

{
	Id: 1634
	Name: "KN_DOMINATOR"
	Description: "Dominators Presence"
	MaxLevel: 3
	Hit: "BDT_SKILL"
	SkillType: {
		Self: true
	}
	DamageType: {
		NoDamage: true
	}
	InterruptCast: true
	SkillData1: 15000
	CoolDown: 0
	Requirements: {
		SPCost: 10
	}
	Unit: {
		Id: 0xe2
		Layout: {
		Lv1: 2
		Lv2: 3
		Lv3: 4
		Lv4: 2
		Lv5: 2
		Lv6: 2
		Lv7: 2
		Lv8: 2
		Lv9: 2
		Lv10: 2
	}
		Interval: 500
		Target: "All"
	}
},

So as you can see the bottom half has the UNT section right? not all skills have that only skills that actually have AOE like storm gust... arrow shower... things like that . . . so the skill i just posted gets bigger every stage, and the way i have it work is that when my Lord Knight gets kill he gets combo spirits, and then when he has 5 he can advance to the next stage , I cant tell you exactly how i made it into an aura that follows me around so your just gonna have to play around with skills that already have that feature. . . 

dominator.png

Not much left i can tell you about UNT_ things, its up to you to play with it, im not really in a rush so i havnt figured out a way to reuse a unt_ more then just the sizes/intervals but it is very possible. . . 

 

Ok now you know brandish spear actually is the most unique skill in pre re, no other skill functions like it and im gonna post one of my custom gunslinger skills that uses the same function as brandish spear, OK you will have to make 2 changes in order for this to actually work 

You need to identify it in your 

skill.h

void (*brandishspear) (struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag);
	void (*jumpshot) (struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag);
	void (*brandishspear_first) (struct square *tc, uint8 dir, int16 x, int16 y);
	void (*brandishspear_dir) (struct square* tc, uint8 dir, int are);
	void (*jumpshot_first) (struct squareb *tc, uint8 dir, int16 x, int16 y);
	void (*jumpshot_dir) (struct squareb* tc, uint8 dir, int are);

Once you identify/declare it, we can start working in our skill.c

Your gonna wanna write this under the brandish spear function .. 

Just crtl+f for this 

void skill_brandishspear

Its a alot shorter then mine because it uses fancy c++ functions that you really dont need to use. So just look at what i wrote. 

 

//JUMPSHOT
struct squareb {
	int val1[50];
	int val2[50];
};

void skill_jumpshot_first (struct squareb *tc, uint8 dir, int16 x, int16 y)
{
	nullpo_retv(tc);

	if(dir == 0){
		tc->val1[0]=x;
		tc->val1[1]=x+1;
		tc->val1[2]=x-1;
		tc->val1[3]=x;
		tc->val1[4]=x+1;
		tc->val1[5]=x+1;
		tc->val1[6]=x;
		tc->val1[7]=x+1;
		tc->val1[8]=x-1;
		tc->val1[9]=x;
		tc->val1[10]=x+1;
		tc->val1[11]=x-1;
		tc->val1[12]=x;
		tc->val1[13]=x+1;
		tc->val1[14]=x-1;
		tc->val1[15]=x;
		tc->val1[16]=x+1;
		tc->val1[17]=x-1;
		tc->val2[0]=y;
		tc->val2[1]=y;
		tc->val2[2]=y;
		tc->val2[3]=y-1;
		tc->val2[4]=y-1;
		tc->val2[5]=y-1;
		tc->val2[6]=y-2;
		tc->val2[7]=y-2;
		tc->val2[8]=y-2;
		tc->val2[9]=y-3;
		tc->val2[10]=y-3;
		tc->val2[11]=y-3;
		tc->val2[12]=y-4;
		tc->val2[13]=y-4;
		tc->val2[14]=y-4;
		tc->val2[15]=y+1;
		tc->val2[16]=y+1;
		tc->val2[17]=y+1;
	} else if(dir==2){
		tc->val1[0]=x+3;
		tc->val1[1]=x+3;
		tc->val1[2]=x+3;
		tc->val1[3]=x+4;
		tc->val1[4]=x+4;
		tc->val1[5]=x+4;
		tc->val1[6]=x+2;
		tc->val1[7]=x+2;
		tc->val1[8]=x+2;
		tc->val1[9]=x+1;
		tc->val1[10]=x+1;
		tc->val1[11]=x+1;
		tc->val1[12]=x-1;
		tc->val1[13]=x-1;
		tc->val1[14]=x-1;
		tc->val1[15]=x;
		tc->val1[16]=x;
		tc->val1[17]=x;
		tc->val2[0]=y;
		tc->val2[1]=y+1;
		tc->val2[2]=y-1;
		tc->val2[3]=y;
		tc->val2[4]=y+1;
		tc->val2[5]=y+1;
		tc->val2[6]=y;
		tc->val2[7]=y+1;
		tc->val2[8]=y-1;
		tc->val2[9]=y;
		tc->val2[10]=y+1;
		tc->val2[11]=y-1;
		tc->val2[12]=y;
		tc->val2[13]=y+1;
		tc->val2[14]=y-1;
		tc->val2[15]=y;
		tc->val2[16]=y+1;
		tc->val2[17]=y-1;
	} else if(dir==4){
		tc->val1[0]=x;
		tc->val1[1]=x+1;
		tc->val1[2]=x-1;
		tc->val1[3]=x;
		tc->val1[4]=x+1;
		tc->val1[5]=x+1;
		tc->val1[6]=x;
		tc->val1[7]=x+1;
		tc->val1[8]=x-1;
		tc->val1[9]=x;
		tc->val1[10]=x+1;
		tc->val1[11]=x-1;
		tc->val1[12]=x;
		tc->val1[13]=x+1;
		tc->val1[14]=x-1;
		tc->val1[15]=x;
		tc->val1[16]=x+1;
		tc->val1[17]=x-1;
		tc->val2[0]=y;
		tc->val2[1]=y;
		tc->val2[2]=y;
		tc->val2[3]=y+1;
		tc->val2[4]=y+1;
		tc->val2[5]=y+1;
		tc->val2[6]=y+2;
		tc->val2[7]=y+2;
		tc->val2[8]=y+2;
		tc->val2[9]=y+3;
		tc->val2[10]=y+3;
		tc->val2[11]=y+3;
		tc->val2[12]=y+4;
		tc->val2[13]=y+4;
		tc->val2[14]=y+4;
		tc->val2[15]=y-1;
		tc->val2[16]=y-1;
		tc->val2[17]=y-1;
	} else if(dir==6){
		tc->val1[0]=x-3;
		tc->val1[1]=x-3;
		tc->val1[2]=x-3;
		tc->val1[3]=x-4;
		tc->val1[4]=x-4;
		tc->val1[5]=x-4;
		tc->val1[6]=x-2;
		tc->val1[7]=x-2;
		tc->val1[8]=x-2;
		tc->val1[9]=x-1;
		tc->val1[10]=x-1;
		tc->val1[11]=x-1;
		tc->val1[12]=x+1;
		tc->val1[13]=x+1;
		tc->val1[14]=x+1;
		tc->val1[15]=x;
		tc->val1[16]=x;
		tc->val1[17]=x;
		tc->val2[0]=y;
		tc->val2[1]=y+1;
		tc->val2[2]=y-1;
		tc->val2[3]=y;
		tc->val2[4]=y+1;
		tc->val2[5]=y+1;
		tc->val2[6]=y;
		tc->val2[7]=y+1;
		tc->val2[8]=y-1;
		tc->val2[9]=y;
		tc->val2[10]=y+1;
		tc->val2[11]=y-1;
		tc->val2[12]=y;
		tc->val2[13]=y+1;
		tc->val2[14]=y-1;
		tc->val2[15]=y;
		tc->val2[16]=y+1;
		tc->val2[17]=y-1;
	} else if(dir==1){
		tc->val1[0]=x;
		tc->val1[1]=x+1;
		tc->val1[2]=x+2;
		tc->val1[3]=x;
		tc->val1[4]=x;
		tc->val1[5]=x+1;
		tc->val1[6]=x+2;
		tc->val1[7]=x+2;
		tc->val1[8]=x+1;
		tc->val1[9]=x+1;
		tc->val1[10]=x+2;
		tc->val1[11]=x+2;
		tc->val1[12]=x+3;		
		tc->val1[13]=x+3;
		tc->val1[14]=x+3;
		tc->val1[15]=x+4;
		tc->val1[16]=x+3;
		tc->val1[17]=x+4;
		tc->val1[18]=x+4;
		tc->val2[0]=y;
		tc->val2[1]=y;
		tc->val2[2]=y;
		tc->val2[3]=y-1;
		tc->val2[4]=y-2;
		tc->val2[5]=y-1;
		tc->val2[6]=y-1;
		tc->val2[7]=y-2;
		tc->val2[8]=y-2;
		tc->val2[9]=y-3;
		tc->val2[10]=y-3;
		tc->val2[11]=y-4;
		tc->val2[12]=y-4;
		tc->val2[13]=y-1;
		tc->val2[14]=y-2;
		tc->val2[15]=y-2;
		tc->val2[16]=y-3;
		tc->val2[17]=y-3;
		tc->val2[18]=y-4;
	} else if(dir==3){
		tc->val1[0]=x+4;
		tc->val1[1]=x+4;
		tc->val1[2]=x+4;
		tc->val1[3]=x+3;
		tc->val1[4]=x+3;
		tc->val1[5]=x+3;
		tc->val1[6]=x+3;
		tc->val1[7]=x+2;
		tc->val1[8]=x+2;
		tc->val1[9]=x+2;
		tc->val1[10]=x+2;
		tc->val1[11]=x+2;
		tc->val1[12]=x+1;
		tc->val1[13]=x+1;
		tc->val1[14]=x+1;
		tc->val1[15]=x+1;
		tc->val1[16]=x;
		tc->val1[17]=x;
		tc->val1[18]=x;
		tc->val2[0]=y+4;
		tc->val2[1]=y+3;
		tc->val2[2]=y+2;
		tc->val2[3]=y+4;
		tc->val2[4]=y+3;
		tc->val2[5]=y+2;
		tc->val2[6]=y+1;
		tc->val2[7]=y+4;
		tc->val2[8]=y+3;
		tc->val2[9]=y+2;
		tc->val2[10]=y+1;
		tc->val2[11]=y;
		tc->val2[12]=y+3;		
		tc->val2[13]=y+2;
		tc->val2[14]=y+1;
		tc->val2[15]=y;
		tc->val2[16]=y+2;
		tc->val2[17]=y+1;
		tc->val2[18]=y;	
	} else if(dir==5){
		tc->val1[0]=x-4;
		tc->val1[1]=x-3;
		tc->val1[2]=x-2;
		tc->val1[3]=x-4;
		tc->val1[4]=x-3;
		tc->val1[5]=x-2;
		tc->val1[6]=x-1;
		tc->val1[7]=x-4;
		tc->val1[8]=x-3;
		tc->val1[9]=x-2;
		tc->val1[10]=x-1;
		tc->val1[11]=x;
		tc->val1[12]=x-3;		
		tc->val1[13]=x-2;
		tc->val1[14]=x-1;
		tc->val1[15]=x;
		tc->val1[16]=x-2;
		tc->val1[17]=x-1;
		tc->val1[18]=x;
		tc->val2[0]=y+4;
		tc->val2[1]=y+4;
		tc->val2[2]=y+4;
		tc->val2[3]=y+3;
		tc->val2[4]=y+3;
		tc->val2[5]=y+3;
		tc->val2[6]=y+3;
		tc->val2[7]=y+2;
		tc->val2[8]=y+2;
		tc->val2[9]=y+2;
		tc->val2[10]=y+2;
		tc->val2[11]=y+2;
		tc->val2[12]=y+1;
		tc->val2[13]=y+1;
		tc->val2[14]=y+1;
		tc->val2[15]=y+1;
		tc->val2[16]=y;
		tc->val2[17]=y;
		tc->val2[18]=y;
	} else if(dir==7){
		tc->val1[0]=x-4;
		tc->val1[1]=x-3;
		tc->val1[2]=x-2;
		tc->val1[3]=x-4;
		tc->val1[4]=x-3;
		tc->val1[5]=x-2;
		tc->val1[6]=x-1;
		tc->val1[7]=x-4;
		tc->val1[8]=x-3;
		tc->val1[9]=x-2;
		tc->val1[10]=x-1;
		tc->val1[11]=x;
		tc->val1[12]=x-3;		
		tc->val1[13]=x-2;
		tc->val1[14]=x-1;
		tc->val1[15]=x;
		tc->val1[16]=x-2;
		tc->val1[17]=x-1;
		tc->val1[18]=x;
		tc->val2[0]=y-4;
		tc->val2[1]=y-4;
		tc->val2[2]=y-4;
		tc->val2[3]=y-3;
		tc->val2[4]=y-3;
		tc->val2[5]=y-3;
		tc->val2[6]=y-3;
		tc->val2[7]=y-2;
		tc->val2[8]=y-2;
		tc->val2[9]=y-2;
		tc->val2[10]=y-2;
		tc->val2[11]=y-2;
		tc->val2[12]=y-1;
		tc->val2[13]=y-1;
		tc->val2[14]=y-1;
		tc->val2[15]=y-1;
		tc->val2[16]=y;
		tc->val2[17]=y;
		tc->val2[18]=y;
	}

}

void skill_jumpshot_dir (struct squareb* tc, uint8 dir, int are)
{
	int c;
	nullpo_retv(tc);

	for( c = 0; c < 50; c++ ) {
		switch( dir ) {
			case 0:                   tc->val2[c]+=are; break;
			case 1: tc->val1[c]-=are; tc->val2[c]+=are; break;
			case 2: tc->val1[c]-=are;                   break;
			case 3: tc->val1[c]-=are; tc->val2[c]-=are; break;
			case 4:                   tc->val2[c]-=are; break;
			case 5: tc->val1[c]+=are; tc->val2[c]-=are; break;
			case 6: tc->val1[c]+=are;                   break;
			case 7: tc->val1[c]+=are; tc->val2[c]+=are; break;
		}
	}
}

void skill_jumpshot(struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag)
{
	int c,n=49;
	uint8 dir;
	struct squareb tc;
	int x, y;

	nullpo_retv(bl);
	x = bl->x;
	y = bl->y;
	dir = map->calc_dir(src, x, y);
	skill->jumpshot_first(&tc,dir,x,y);
	skill->jumpshot_dir(&tc,dir,4);
	skill->area_temp[1] = bl->id;


	for(c=0;c<50;c++){
		if(c==0||c==50) skill->jumpshot_dir(&tc,dir,-1);
		map->foreachincell(skill->area_sub,
			bl->m,tc.val1[c%25],tc.val2[c%25],BL_CHAR,
			src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1,
			skill->castend_damage_id);
	}
}

asdasd.png

 

Youll notice i have 8 directions... its the same as when you place an npc and chose what way you want it to face. Its not gonna make much sense if you just look at it, so i recommend drawing it on grid paper and just TRY to see where these numbers X/Y actually fit... its really wonky but once you see it youll be like shit this is easy. 

Ok im gonna post my desperado as well but were using the same functions as firewall in this skill soo youve probably seen this and thought oh i can play with this and it turns out to be really fucked up... working with this function is alot easier because its just centered on you compared to brandish spear which has 8 directions, and they start from a corner that i cant explain, like i said, draw it on paper , once you see it youll catch on quick. 

first go to your 

skill.h

find this 

#define MAX_SKILL_UNIT_LAYOUT     65

its not gonna be 65 in your SRC cause i already raised it. 

Now go to 

skill.c (Your probably gonna wanna test it out a bit and practise with a skill that already uses this style of grid Wall of thorn would be easy to follow cause thats where i placed my desperado 

			case GS_DESPERADO: {
					static const int dx[] = {-4,-4,-4,-4,-4,-4,-4,-3,-3,-3,-3,-3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1};
					static const int dy[] = { 3, 2, 1, 0,-1,-2,-3, 4, 3, 2, 1, 0,-1,-2,-3,-4, 4, 3, 2,-2,-3,-4, 4, 3,-4,-3,-4,-3, 4, 3, 3, 2, 1, 0,-1,-2,-3, 4, 3, 2, 1, 0,-1,-2,-3,-4, 4, 3, 2,-2,-3,-4, 4, 3,-4,-3};
					skill->dbs->unit_layout[pos].count = 56;
					memcpy(skill->dbs->unit_layout[pos].dx,dx,sizeof(dx));
					memcpy(skill->dbs->unit_layout[pos].dy,dy,sizeof(dy));
				}
				break;

Ok so the first cell would be -4,3 .. . . the next cell is -4,2 then -4,1 -4,0 -4,-1 -4-2

Look at the top one and the one under it, thats the cell that it will hit. 

Change the UNIT_LAYOUT[pos].count =   - - - - number to match the amount of cells so i made desperado a 56 cell skill that circles around me, but it leaves a small gap so that monsters directly in front or around me dont get it. Draw it. 

and this is what my desperado looks like in my skill.db 

{
	Id: 516
	Name: "GS_DESPERADO"
	Description: "Desperado"
	MaxLevel: 30
	Hit: "BDT_MULTIHIT"
	SkillType: {
		Self: true
	}
	AttackType: "Weapon"
	Element: "Ele_Weapon"
	AfterCastActDelay: 0
	AfterCastWalkDelay: 1500
	SkillData1: 25
	CoolDown: 500
	Requirements: {
		SPCost: {
			Lv1: 32
			Lv2: 34
			Lv3: 36
			Lv4: 38
			Lv5: 40
			Lv6: 42
			Lv7: 44
			Lv8: 46
			Lv9: 48
			Lv10: 50
		}
		WeaponTypes: {
			Revolvers: true
		}
		AmmoTypes: {
			A_BULLET: true
		}
		AmmoAmount: 10
	}
	Unit: {
		Id: 0x86
		Layout: -1
		Interval: 100
		Target: "Enemy"
	}
},

UNT ID:0x86 is used EVERYWHERE , arrowshower stormgust..comet meteor they all use the same thing but they have their effects linked client side... this is mostly used for damage skills and the other UNT_s are everything else, sanctuary has its own UNT, all the dances/songs have their own UNT's. . . youll have to look at their ID in the skill db if you wanna re use them somewhere else, but like i said, your gonna have to figure out how to use them in a bunch of different ways right? 

Your probably not gonna be able to make. . . UNT_UGLYDANCE ,  be reused... one 2 different custom skills where one of them stuns everyone around you . . . . and then you have another skill that uses UNT_UGLYDANCE but that one freezes everybody ... im still working on this. 

 

enjoy lol . . i didnt miss anything and i just told you everything i know about UNT_'s and how to use them and how to make custom sizes both ways, in place skills (i know desperado isnt look like a place but it actually kinda is) and the way brandish spear is use, where you click on something and then it has its SPECIFIC area, not just a splash, it has its own pattern,, you can get complicated if you want but i recommend learning from ME and not from what brandish spear function cause that thing is intermidate level C++ and uses a growth function (++) . . . i made it really simple. 

Share this post


Link to post
Share on other sites
  • 0

Youll notice with my jump shot, you can easily make it a ranged skill . . but you need to make sure you fill in the cell THAT YOUR CHARACTER IS STANDING ON OTHERWISE THE SKILL WONT EVEN SET OFF 

 

Seriously i made a seperate post because this is the most important part. 

Share this post


Link to post
Share on other sites
  • 0

Also im working on a formula to apply effects, normally if u try to use specialeffects function. . . 

		case AM_WATER:
				clif_specialeffect(src,54,1);
				clif_specialeffect(bl,208,AREA);
				sc_start(src,bl,SC_SOAKED,100,skill_lv,skill->get_time2(skill_id,skill_lv));
				break;

When you try to use this , if you kill the monster with the skill the effects wont even show and really makes it ugly so what i did is i turn it into a 1 damage MISC skill . . . 

skill.db

{
	Id: 726
	Name: "AM_HARVEST"
	Description: "Harvest"
	MaxLevel: 10
	Range: 2
	Hit: "BDT_SKILL"
	SkillType: {
		Place: true
	}
	SkillInfo: {
		IgnoreLandProtector: true
		AllowReproduce: true
	}
	AttackType: "Misc"
	Element: "Ele_Weapon"
	DamageType: {
		SplashArea: true
		IgnoreFlee: true
	}
	NumberOfHits: -3
	AfterCastActDelay: {
		Lv1: 0
		Lv2: 0
		Lv3: 0
		Lv4: 0
		Lv5: 3000
	}
	AfterCastWalkDelay: {
		Lv1: 2000
		Lv2: 0
		Lv3: 0
		Lv4: 0
		Lv5: 3000
	}
	SkillData1: 1000
	SkillData2: 50000
	CoolDown: 0
	Requirements: {
		SPCost: 15
	}
	Unit: {
		Id: 0x86
		Range: 1
		Interval: 1000
		Target: "Enemy"
		Flag: {
			UF_SKILL: true
		}
	}
},

 

Anyways since the skill only deals 1 damage the effect will apply every time . . . .

But what i did is i made a Status similar to burning (Burning makes numbers appear over your head, poison doesnt) . . . the status actually deals all my damage, so i can kill mobs using special effect funtion, with access to the 1000+ effects in your effects_doc. 

status.h Gotta declare your new SC add it at the bottom

	// Summoner
	SC_SUHIDE,
	SC_SU_STOOP,
	SC_SPRITEMABLE,
	SC_CATNIPPOWDER,
	SC_SV_ROOTTWIST,
	SC_BITESCAR,
	SC_ARCLOUSEDASH,
	SC_TUNAPARTY,
	SC_SHRIMP, // 650
	SC_FRESHSHRIMP,

	SC_DRESS_UP,

	// Rodex
	SC_DAILYSENDMAILCNT,

	// Clan System
	SC_CLAN_INFO,
	
	SC_HARVESTED,

In your status.c

	add_sc( AM_HARVEST  	     , SC_HARVESTED      );

this is where all the other skills are just look for SM_PROVOKE or something lol 

		case SC_FOGWALL:
		case SC_FROSTMISTY:
		case SC_BURNING:
		case SC_HARVESTED:
		case SC_MARSHOFABYSS:

place it here

and here

nullpo_retr(true, sc);
	if (sc->data[SC_REFRESH]) {
		if (type >= SC_COMMON_MIN && type <= SC_COMMON_MAX) // Confirmed.
			return true; // Immune to status ailements
		switch (type) {
			case SC_DEEP_SLEEP:
			case SC__CHAOS:
			case SC_BURNING:
			case SC_HARVESTED:
			case SC_STUN:
			case SC_SLEEP:
			case SC_CURSE:
			case SC_STONE:
			case SC_POISON:
			case SC_BLIND:
			case SC_SILENCE:
			case SC_BLOODING:

and here

	} else if (sc->data[SC_INSPIRATION]) {
		if (type >= SC_COMMON_MIN && type <= SC_COMMON_MAX)
			return true; // Immune to status ailements
		switch (type) {
			case SC_POISON:
			case SC_BLIND:
			case SC_STUN:
			case SC_SILENCE:
			case SC__CHAOS:
			case SC_STONE:
			case SC_SLEEP:
			case SC_BLOODING:
			case SC_CURSE:
			case SC_HARVESTED:
			case SC_BURNING:
			case SC_FROSTMISTY:
			case SC_FREEZE:
			case SC_COLD:

(Im actually not 100% on what OPT s do but i placed it here

	opt_flag = 1;
	switch(type) {
		case SC_STONE:
		case SC_FREEZE:
		case SC_STUN:
		case SC_SLEEP:
		case SC_BURNING:
		case SC_HARVESTED:
		case SC_WHITEIMPRISON:
		case SC_COLD:
			sc->opt1 = 0;
			break;

Looking through this again i just realized i didnt use SC_BURNING but actually made it a poison lmao... but it works its up to you to test it and clean it and learn it........... this is just some random way to apply skill damage with ALL THE EFFECTS and make COMPLETLY NEW SKILLS 

case SC_POISON:
			if (st->hp <= max(st->max_hp / 10, sce->val4)) //Stop damaging after 25% HP left.
				break;
			FALLTHROUGH
		case SC_HARVESTED:
		case SC_DPOISON:
			if (--(sce->val3) > 0) {
				if (sc->data[SC_SLOWPOISON] != NULL) {
					sc_timer_next(1000 + tick, status->change_timer, bl->id, data);
					return 0;
				}
				if (sce->val2 != 0 && bl->type == BL_MOB) {
					struct block_list* src = map->id2bl(sce->val2);
					if (src != NULL)
						mob->log_damage(BL_UCAST(BL_MOB, bl), src, sce->val4);
				}
				map->freeblock_lock();
				status_zap(bl, sce->val4, 0);
				if (sc->data[type] != NULL) { // Check if the status still last (can be dead since then).
					sc_timer_next(1000 + tick, status->change_timer, bl->id, data);
				}
				map->freeblock_unlock();
				return 0;
			}
			break;
		case SC_POISON:
		case SC_DPOISON:
			data.tick = sc->data[i]->val3 * 1000;
			break;
		case SC_HARVESTED:
			data.tick = sc->data[i]->val3 * 1000;
			break;
		case SC_FEAR:
		case SC_LEECHESEND:
			data.tick = sc->data[i]->val4 * 1000;
			break;

 

I hope you grasp my idea here, you can even make a formula that takes all your stats into account but im still working on make a REAL meta formula not something that just does 1000 more damge every skill level.  . . ill post that some day 

Super experimental post.

Summed up : 

" using specialeffect funtion, doesnt show the effect when YOU KILL THE MOB WITH THE SKILL, so long as it still has HP the effect will show, So making a 1 damage skill and giving it a very specific damage formula ( Poison in this case cause this is in my farming minigame but YOU CAN MAKE A DAMAGE FORMULA BY CALLING ATK MARK STR LEVEL ETC ETC ) Just look at SC_BURNING " 

Look ill even show you an example 

case SC_BURNING:
			if( --(sce->val4) > 0 ) {
				struct block_list *src = map->id2bl(sce->val3);
				int damage = 1000 + 3 * status_get_max_hp(bl) / 100; // Deals fixed (1000 + 3%*MaxHP)

				map->freeblock_lock();
				clif->damage(bl,bl,0,0,damage,1,BDT_MULTIENDURE,0); //damage is like endure effect with no walk delay
				status->damage(src, bl, damage, 0, 0, 1);

				if( sc->data[type]){ // Target still lives. [LimitLine]
					sc_timer_next(3000 + tick, status->change_timer, bl->id, data);
				}
				map->freeblock_unlock();
				return 0;
			}
			break;
		case SC_LOCKEDB:
			if( --(sce->val4) > 0 ) {
				struct block_list *src = map->id2bl(sce->val3);
				int damage =  (100 - (st->def)) * (50 * (sce->val1));	
				
				map->freeblock_lock();
				clif->damage(bl,bl,0,0,damage/100,1,BDT_MULTIENDURE,0); //damage is like endure effect with no walk delay
				status->damage(src, bl, damage/100, 0, 0, 1);

				map->freeblock_unlock();
				return 0;
			}
			break;

Look at INT DAMAGE = 

Val1 is my SKILL LEVEL 

and im calling the TARGET DEFENSE. . . . So Yes this skill does damage and does less damage based on the targets defence and my skill level....

 

Super experimental 

Good luck with this part , its really ugly but its all i could figure out for now 

 

Oh if you dont know how to make a skill MISC damage, just copy TF_THROWSTONE and go in the battle.c and and copy it there too 

 

Edited by lllaaazzz

Share this post


Link to post
Share on other sites
  • 0

Ok another thing i forgot to add,

If you wanna increase the amount of cells you can target with the brnadishspear function you need to change these numbers 

void skill_jumpshot(struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag)
{
	int c,n=49;
	uint8 dir;
	struct squareb tc;
	int x, y;

	nullpo_retv(bl);
	x = bl->x;
	y = bl->y;
	dir = map->calc_dir(src, x, y);
	skill->jumpshot_first(&tc,dir,x,y);
	skill->jumpshot_dir(&tc,dir,4);
	skill->area_temp[1] = bl->id;


	for(c=0;c<50;c++){
		if(c==0||c==50) skill->jumpshot_dir(&tc,dir,-1);
		map->foreachincell(skill->area_sub,
			bl->m,tc.val1[c%25],tc.val2[c%25],BL_CHAR,
			src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1,
			skill->castend_damage_id);
	}
}

line 17 and 18 and 19

    for(c=0;c<50;c++){
        if(c==0||c==50) skill->jumpshot_dir(&tc,dir,-1);
        map->foreachincell(skill->area_sub,
            bl->m,tc.val1[c%25],tc.val2[c%25],BL_CHAR,

 

Increase these numbers, However im not 100% about the c%25],tc.val2[c%25] . . .. I raised it, it works well for me so raise it if you get problems

Line 3

    int c,n=49;
 

raise that to -1 of what you made in 17 ,18 so i put 49 cause i made my max 50.

 

 

Ok 

void skill_jumpshot_dir (struct squareb* tc, uint8 dir, int are)
{
	int c;
	nullpo_retv(tc);

	for( c = 0; c < 50; c++ ) {
		switch( dir ) {
			case 0:                   tc->val2[c]+=are; break;
			case 1: tc->val1[c]-=are; tc->val2[c]+=are; break;
			case 2: tc->val1[c]-=are;                   break;
			case 3: tc->val1[c]-=are; tc->val2[c]-=are; break;
			case 4:                   tc->val2[c]-=are; break;
			case 5: tc->val1[c]+=are; tc->val2[c]-=are; break;
			case 6: tc->val1[c]+=are;                   break;
			case 7: tc->val1[c]+=are; tc->val2[c]+=are; break;
		}
	}
}

Line 6 

    for( c = 0; c < 50; c++ ) {
 

Raise this number to same as what you did at 17

 

 

Ok. . . Im just gonna grab 1 direction to show you this. . . 

tc->val1[0]=x;
		tc->val1[1]=x+1;
		tc->val1[2]=x-1;
		tc->val1[3]=x;
		tc->val1[4]=x+1;
		tc->val1[5]=x+1;
		tc->val1[6]=x;
		tc->val1[7]=x+1;
		tc->val1[8]=x-1;
		tc->val1[9]=x;
		tc->val1[10]=x+1;
		tc->val1[11]=x-1;
		tc->val1[12]=x;
		tc->val1[13]=x+1;
		tc->val1[14]=x-1;
		tc->val1[15]=x;
		tc->val1[16]=x+1;
		tc->val1[17]=x-1;
		tc->val2[0]=y;
		tc->val2[1]=y;
		tc->val2[2]=y;
		tc->val2[3]=y-1;
		tc->val2[4]=y-1;
		tc->val2[5]=y-1;
		tc->val2[6]=y-2;
		tc->val2[7]=y-2;
		tc->val2[8]=y-2;
		tc->val2[9]=y-3;
		tc->val2[10]=y-3;
		tc->val2[11]=y-3;
		tc->val2[12]=y-4;
		tc->val2[13]=y-4;
		tc->val2[14]=y-4;
		tc->val2[15]=y+1;
		tc->val2[16]=y+1;
		tc->val2[17]=y+1;

I hope you can graps that 

tc->val1[0]

and 

tc->val2[0]

 

Are the first coordiantes so [1] and [1] go together [2] and [2] etc etc 

 

 

and finally 

struct squareb {
	int val1[50];
	int val2[50];
};

Actually this im not 100% aswell because in skill.h they wrote a bit about this but. . . .So raise this, and then if you ever do have problems go to your.......

Skill.h 

#define MAX_SQUARE_LAYOUT         5 // 11*11 Placement of a maximum unit
#define MAX_SKILL_UNIT_COUNT      ((MAX_SQUARE_LAYOUT*2+1)*(MAX_SQUARE_LAYOUT*2+1))

If you ever get problems your probably gonna have to tweak these numbers

 

 

 

 

Share this post


Link to post
Share on other sites
  • 0
On 2/3/2019 at 7:29 PM, Rotciv said:

I have it saved, don't worry

Also you can pm me on rathena forums same name if you have problems changing the maximum cause i already made it 50 and pretty sure the only line youll need to to tweak is the 2 parts that are c%25],tc.val2[c%25]

 

 

these guys are shit 

Share this post


Link to post
Share on other sites
  • 0

@lllaaazzz Thanks for all your help! It surely will help me alot. I'll start next week to look at everything about it, got a lot of stuff to do at this one.
Can I pm you on rathena forum if I have any other problems? (or discord or whatever hahah)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now