Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Zelda 1 Style Random drops
- //v0.3
- //For 2.55
- //By: ZoriaRPG
- //17th February, 2019
- script typedef ffc class;
- class script Z1enemydrop
- {
- void run(){}
- int killcount[2];
- const int KILL_NORMAL;
- const int KILL_CONSEC;
- const int DROPSET_A = 0;
- const int DROPSET_B = 1;
- const int DROPSET_C = 2;
- const int DROPSET_D = 3;
- const int DROPSET_X = 4;
- const int DROPSET_M = 5; MAGIC, 100%
- const int DROPSET_V = 6; //Vire splits increase the count, but do not drop items.
- const int DROP_X_OFS = 0;
- const int DROP_Y_OFS = 0;
- int chances[] = {31,41,59,41, 0, 100};
- int lists[4*10]=
- {
- I_RUPEE, I_HEART, I_RUPEE, I_FAIRY, I_RUPEE, I_HEART, I_HEART, I_RUPEE, I_HEART, I_HEART,
- I_BOMB, I_RUPEE, I_CLOCK, I_RUPEE, I_HEART, I_BOMB, I_RUPEE, I_BOMB, I_HEART, I_HEART,
- I_RUPEE, I_HEART, I_RUPEE, I_RUPEE5, I_HEART, I_CLOCK, I_RUPEE, I_RUPEE, I_RUPEE, I_RUPEE5,
- I_HEART, I_FAIRY. I_RUPEE, I_HEART, I_FAIRY, I_HEART, I_HEART, I_HEART, I_RUPEE, I_HEART,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 //Vires when they only split, will increment counts, bu never drop items
- };
- //The dropset that a given enemy uses; SPLITTERS NEED SPECIAL HANDLING?
- //This could instead be an enemy editor attribute fied of some sort. rather than an array,
- //so that the questmaker can customise it.
- int enemydropsets[]=
- {
- //guys
- DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- //enemies start here
- DROPSET_A, DROPSET_B, DROPSET_A, DROPSET_B, DROPSET_A,
- DROPSET_C, DROPSET_C, DROPSET_A, DROPSET_A, DROPSET_B,
- DROPSET_D, DROPSET_C, DROPSET_D, DROPSET_D, DROPSET_X,
- //GHINI2 ?PHANTOM
- DROPSET_C, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_C, DROPSET_X, DROPSET_C, DROPSET_C,
- DROPSET_B, DROPSET_D, DROPSET_X, DROPSET_C, DROPSET_B,
- DROPSET_D, DROPSET_X, DROPSET_B, DROPSET_X, DROPSET_B,
- DROPSET_C, DROPSET_B, DROPSET_A, DROPSET_D, DROPSET_D,MOLDORM
- DROPSET_D, DROPSET_D, DROPSET_D, DROPSET_D, DROPSET_D,
- DROPSET_D, DROPSET_X, DROPSET_X, DROPSET_D, DROPSET_D,
- DROPSET_D, DROPSET_D, DROPSET_D, DROPSET_D, DROPSET_D, //LANMOLA
- DROPSET_C, DROPSET_D, DROPSET_D, DROPSET_X, DROPSET_C,
- DROPSET_C, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_B, DROPSET_D, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_B, DROPSET_D, DROPSET_D, DROPSET_D,
- DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_B,
- DROPSET_A, DROPSET_C, DROPSET_C, DROPSET_D, DROPSET_D,
- DROPSET_D, DROPSET_M, DROPSET_A, DROPSET_A, DROPSET_D,
- DROPSET_D, DROPSET_D, DROPSET_D, DROPSET_A, DROPSET_D,
- DROPSET_D, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_C, DROPSET_D, DROPSET_D, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_D, DROPSET_A, DROPSET_B, DROPSET_B,
- DROPSET_B, DROPSET_B, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_X, DROPSET_B, DROPSET_A, DROPSET_X,
- DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X, DROPSET_X,
- DROPSET_X, DROPSET_X, DROPSET_C, DROPSET_X, DROPSET_C,
- DROPSET_A, DROPSET_X, DROPSET_X, DROPSET_D, DROPSET_D,
- DROPSET_M, DROPSET_C, DROPSET_D, DROPSET_D, DROPSET_M,
- DROPSET_X, DROPSET_X, DROPSET_X
- };
- int getChance(int enemyid)
- {
- return chances[enemydropsets[enemyid]];
- }
- bool canDrop(int enemy_id)
- {
- return ( Rand(1,100) <= getChance(enemy_id) );
- }
- void doDrop(npc n)
- {
- if ( n->HP > 0 ) return; //wait until dead
- bool ignore = false;
- switch(n->Family)
- {
- case NPCT_MOLDORM:
- case NPCT_MANHANDLA:
- case NPCT_GLEEOK:
- case NPCT_LANMOLA:
- case NPCT_PATRA:
- {
- if ( !n->isCore ) ignore = true; break;
- }
- case NPCT_DODONGO: ignore = true; break; //These never drop items, AFAIK.
- default: break;
- }
- if ( !ignore )
- {
- if ( canDrop(n->ID) )
- {
- int drp_itm_id = lists[enemydropsets[n->ID]+killcount[KILL_NORMAL]];
- switch(killcount[KILL_CONSEC])
- {
- begin insane Z1 consecutive drop rules.
- case 10: drp_itm_id = I_BOMBAMMO1; break;
- case 16: drp_itm_id = I_FAIRY; break;
- default: break;
- /*
- TO IMPLEMENT
- Advanced strategies: If a forced bomb/rupee or forced fairy drops,
- the consecutive counter for bombs/rupees is reset, but not the counter
- for fairies. So no matter how many hits you get on Manhandla with one
- well-placed bomb, the 10 count is reset after defeating him.
- The same is true of Dodongo. Likewise with a "Hippo Fairy"
- (going into a Patra with 7 on the consecutive counters, so that the
- Patra's center will be kill #16 and get a fairy), the bomb/rupee count
- resets to 0. Credit to Khananaphone for this discovery.
- This means that if you get a forced fairy drop, the next
- consecutive bomb/rupee kill will not be at 20. It will be at 26.
- So bomb/rupee drops work in one of two methods:
- 10, (Fairy at 16), 26, 36, 46...
- 10, (Skip fairy at 16 by killing non-dropping enemy), 20, 30, 40...
- */
- }
- item drp = Screen->CreateItem(drp_itm_id);
- drp->X = n->X + DROP_X_OFS; drp->Y = n->Y + DROP_Y_OFS;
- drp->Pickup = IP_TIMEOUT;
- ( killcount[KILL_NORMAL] < 9 ) ? ++killcount[KILL_NORMAL] : killcount[KILL_NORMAL] = 0;
- ++killcount[KILL_CONSEC]; //when does this roll over on the NES?
- }
- }
- }
- void resetKillcount()
- {
- if ( Link->InvFrames ) killcount[KILL_CONSEC] = 0;
- }
- }
- link script LinkZ1
- {
- void run()
- {
- while(1)
- {
- Z1enemydrop.resetKillcount();
- for ( int q = Screen->NumNPCs(); q > 0; --q )
- {
- npc n = Screen->LoadNPC(q);
- Z1enemydrop.doDrop(n);
- }
- }
- }
- /*
- Forced drops
- Some item drops can be forced and take priority over the standard drop system.
- Forced drops are handled by two consecutive kill counters and a bomb flag.
- The first counter, the ten count ($50), controls whether a forced 5 rupee is dropped.
- The bomb flag ($51) controls whether the ten count drop should be a bomb, instead.
- The second counter, the fairy count ($0627), controls whether fairies are dropped.
- All of these variables are cleared when Link collides with an enemy (including bubbles and
- even the recorder whirlwind).
- When Link kills an enemy (that is, the enemy makes a dying sound), both counters are incremented.
- This occurs at kill time, before the dying animation.
- Item drops occur later, after the dying animation completes. When the drop is calculated,
- the game checks the counters to decide what to drop. If the fairy count is 16, then a fairy is
- dropped and the ten count and bomb flag are cleared. Otherwise, if the ten count is 10,
- either a 5 rupee is dropped if the bomb flag is clear or a bomb is dropped if the flag is set,
- and the ten count and bomb flag are then cleared. So, in the case of any forced drop,
- the ten count and bomb flag are cleared, but the fairy count is not.
- Some enemies cannot drop items. Because they don't run the drop code, they also can't
- drop forced items, and thus won't consume the counters. These enemies are those in the
- no-drop group, as well as stalfos, gibdos, and like likes in slot 1
- (because these enemies may be carrying the room treasure, and it would be undesirable
- if they dropped both the treasure and an item). We'll call these no-drop enemies.
- If the ten count transitions from 9 to 10 due to a bomb kill, the bomb flag is set.
- The ten count cannot exceed 10 and will hold at that value even if additional
- kills occur before the forced item can be dropped, such as by killing a group of
- enemies at once or killing no-drop enemies.
- Once any forced drop occurs, the counter is reset to 0.
- The fairy counter, however, has no hard limit.
- It will continue to increase with each kill.
- Because of this, the fairy drop can be skipped.
- Any drop occurring when the fairy counter is 16 will be a fairy, so killing a
- group of enemies to bring the count above 16 at drop time will skip the fairy.
- Alternatively, because no-drop enemies can't drop forced items,
- they can die with the counter at 16 without performing the drop.
- Skipping the fairy will avoid resetting the ten count and bomb flag.
- Because the fairy counter isn't cleared when the drop occurs, multiple
- fairies can be dropped from the same count. For example, if the counter is
- 12 and 4 enemies are quickly killed before any of them can calculate a drop,
- the counter will be 16 when the drops are handled, so all 4 drops will be fairies.
- Note that while the fairy counter has no hard limit, it is an 8-bit value and will
- overflow to 0 at 256 kills, allowing it to force more fairies at the next 16.
- There are some notable special cases and edge cases with counters. These include:
- Dodongos: Killing a dodongo does not increment either counter, whether killed with
- bombs or the sword. If the dodongo is killed with a sword, however,
- the ten count is set to 10 and the bomb flag is set, forcing a bomb at drop time.
- This method of forcing the bomb can result in unexpected behavior.
- If Link takes a hit after killing the dodongo, but before the drop, the forced bomb
- will be lost. Furthermore, if the fairy count is 16 when the drop occurs, the fairy
- will be dropped instead of the bomb and the ten count and bomb flag will be cleared.
- Finally, if Link kills a second dodongo with a sword before the first one has dropped
- its bomb, the second will not drop a bomb because the forced drop system has no way of
- queuing up multiple forced bombs.
- Vulnerable unkillable enemies: Enemies such as the manhandla core and flying
- gleeok heads are invincible, but actually handle weapon collision and will
- clear their iframes and unkill themselves each frame. This means they count as a
- kill every frame that a weapon is touching them. Bombing these enemies is a good
- way to force a bomb because it will quickly max out the ten count and set
- the bomb flag, but it will also be adding to the fairy counter, which could override
- the bomb drop when killing the boss. The old man in the dungeon also behaves this way,
- but because he doesn't clear his iframes, he'll only count as one kill per attack.
- Multi-part enemies: Manhandla's hands, gleeok's attached heads, and moldorm's
- and lanmola's segments each increment the consecutive counters when killed,
- but the death of the whole enemy does not grant an additional consecutive kill;
- that is, killing the last part will only add 1 to the counters, not 2.
- A perfect bomb on manhandla will increase the counters by 5 instead of 4,
- though, because the core is also hit and counts as a kill.
- Leader enemies: When a ringleader (such as the level 2 goriya leader) is killed,
- the other enemies in the room die by being directly transitioned to the dying state
- (by setting dynamic_spawn_state to #$10) and will not impact the consecutive counters.
- The ringleader itself counts as normal, however. Ghini leaders also share this same
- behavior (through a similar mechanism).
- Zols: While splitting enemies (zols and vires) don't normally count as kills
- when split, zols are vulnerable to an additional weapon hit on the frame they
- split, allowing them to be killed and counted as a consecutive kill.
- This is due to a bug where zols delete themselves before splitting
- (in case there aren't enough slots for the gels they're creating),
- but instead of exiting immediately afterward, their AI continues to do
- meaningful work on the deleted object, including collision checks.
- The deletion (through ClearObject at Bank7_FEB1) clears the object_iframes variable,
- which guarantees the zol can take a hit during this one last check.
- Because deletion clears the object's dynamic_id variable, the zol doesn't
- run again and thus can't drop an item nor increment the global counter.
- Its health is not cleared by ClearObject, so the weapons it collides with must
- do enough damage to kill it. Note that if a gel was spawned into the zol's slot,
- the gel will be hit, instead.
- Vires are more robustly written and don't suffer from this bug.
- Overkill: When an enemy is killed by a weapon, it still finishes checking the
- remaining weapons that frame, as normal. This means it can be hit by those additional
- weapons, which may also kill it. The consecutive kill counters are incremented at
- kill time, so these additional kills will each increment the counters like with
- any normal kill. As a result, killing a single enemy by hitting it with multiple
- weapons on one frame can add more than one to the counts.
- This can be done most practically by timing multiple attacks to hit when an enemy's iframes expire.
- Note that the health the enemy has after a killing blow can vary.
- If the weapon damage was equal to the enemy's current health, the resulting health
- is 0, so any following hits will count as kills.
- However, if the damage was more than the current health, the health is unchanged.
- Furthermore, the order in which weapons are checked can impact how many kills the
- enemy gives because each weapon hit may reduce the health for the following weapons.
- Weapon check order is boomerang, beam (sword/rod), flame/bomb slot A, flame/bomb slot B,
- sword, arrow/rod.
- Sub-frame behavior: Because everything in the game must be handled sequentially,
- events handled earlier can directly impact those handled later, so the order of
- execution can result in surprising behavior. For example, if an enemy is killed
- on the same frame that multiple other enemies are dropping items, and that kill
- sets the fairy counter to 16, then any drops handled before the kill was registered
- would be normal random drops, and drops after the kill would be forced fairies,
- despite all of the drops happening on the same frame.
- */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement