Jump to content

Effect Immunities on the EE Engine (aka Taking Full Advantage of the EE Fixpack)


Recommended Posts

A brief overview

There are all sorts of spells, items, and innate abilities throughout the games that provide immunities to various effects: immunity to sleep, immunity to confusion, and so on and so forth. Providing an immunity is generally straightforward: you block the primary opcodes, and then try to block the normal visuals, portrait icons, strings, and other effects that typically accompany it. These can range from the incredibly simple--immunity to grease just needs to block grease itself, plus the portrait icon--to the horrific--free action requires more than 60 effects to get right.

To that end, the BG2 Fixpack utilized a standard series of batch macros to accomplish this, and published them as a separate library so that other mods could utilize them. For the most part these work very well: if you were immune to, say, level drain, you didn't get level-drained nor would you see things like "Two Levels Drained" in your combat feedback. There were gaps, however: because so many spells use the same visual effects to accompany these spells, there were times you couldn't block visuals without collateral damage. Sounds, on the other hand, can't be blocked individually at all unless you farm them out into separate files from the original item or spell. The important bits--the actual effects, portrait icons, and combat feedback--were blocked, so this was generally an acceptable tradeoff.

Enter the Enhanced Edition--or more specifically, the EE Fixpack

Among the many tools that the Enhanced Edition brings to the table, the one that's relevant here is spellstates. This is not going to be a tutorial about creating or using spellstates--basically what we need to know is that spellstates are an arbitrary list of created states that can be applied and detected for usage in effects using, for example, opcodes 324 and 328. (They're also a limited resource, so play nice with others.)

The basic idea being implemented in the EE Fixpack is this:

  1. A series of spellstates that reflect immunities are created, e.g. PANIC_IMMUNITY is for the various items and spells that make you immune to fear.
  2. Spells or items that provide an immunity now set these states. So the Resist Fear spell would set the PANIC_IMMUNITY state on its targets for its duration.
  3. As a fallback, items or spells that provide immunities would still provide the normal suite of effects you'd see from the BG2 Fixpack immunity batches mentioned in the overview--blocking the opcode, associated portrait icons, combat feedback, and the like.
  4. Spells or items that cause the effects will check whether the target is under one of these spellstates, and blocks its effects from every applying. So a spell like Horror or Spook would check if the target if the target has PANIC_IMMUNITY, and block its own effects.

The end result is that you have a substantially cleaner implementation that, if done correctly, also blocks the edge cases of sound effects and other cosmetics bleeding through.

There are some pitfalls, however, mainly centered on point four. It relies on the intrinsic ordering of effects in a spell or item for proper blocking. This is generally straightforward, but when you have effects overlap (e.g. a spell that causes fear and hold) extra care must be taken. We'll discuss these a bit with code from the newly-released Under-Represented Items v9.

Some practical code examples

In anticipation of the EE Fixpack, version 9 of Under-Represented Items is coded with these new immunity spellstates in mind, specifically this block of compatibility code. The first bit is simple:

  // use immunity spellstates, if available (e.g. EE Fixpack)
  OUTER_SET confusion_immunity = IDS_OF_SYMBOL (~splstate~ ~CONFUSION_IMMUNITY~)  
  OUTER_SET death_immunity     = IDS_OF_SYMBOL (~splstate~ ~DEATH_IMMUNITY~)   
  OUTER_SET entangle_immunity  = IDS_OF_SYMBOL (~splstate~ ~ENTANGLE_IMMUNITY~)  
  OUTER_SET haste_immunity     = IDS_OF_SYMBOL (~splstate~ ~HASTE_IMMUNITY~)  
  OUTER_SET hold_immunity      = IDS_OF_SYMBOL (~splstate~ ~HOLD_IMMUNITY~)  
  OUTER_SET panic_immunity     = IDS_OF_SYMBOL (~splstate~ ~PANIC_IMMUNITY~)  
  OUTER_SET silence_immunity   = IDS_OF_SYMBOL (~splstate~ ~SILENCE_IMMUNITY~)   
  OUTER_SET slow_immunity      = IDS_OF_SYMBOL (~splstate~ ~SLOW_IMMUNITY~)  
  OUTER_SET web_immunity       = IDS_OF_SYMBOL (~splstate~ ~WEB_IMMUNITY~)    

This simply sets variables based on a spellstate's value in the IDS, which we'll use in the patches to follow. Note that this is also mod-agnostic: we're not checking if EE Fixpack is installed, we're checking if these spellstates exist. There's no reason why a mod like SCS couldn't also implement the same scheme as the EE Fixpack. If these spellstates do not exist, these variables will be set to -1, which we use as a check to proceed in subsequent patches.

For an item that provides immunities all that needs to be done is the addition of the relevant spellstates. For Under-Represented items, the only example is Lolth's Cruel Sting, a short sword that provides Free Action when equipped. In this case, it should provide the spellstates ENTANGLE_IMMUNITY, HASTE_IMMUNITY, HOLD_IMMUNITY, SLOW_IMMUNITY, and WEB_IMMUNITY. The first step is to check if any of these have a valid variable, and then we simply clone in the new spellstate:

  ACTION_IF ((entangle_immunity > 0) OR (haste_immunity > 0) OR (hold_immunity > 0) OR (slow_immunity > 0) OR (web_immunity > 0))BEGIN // free action... le sigh
  
    COPY_EXISTING ~u#hfssls.itm~ ~override~ // Lolth's Cruel Sting
      PATCH_IF (entangle_immunity > 0) BEGIN
        LPF CLONE_EFFECT INT_VAR multi_match = 1 match_opcode = 101 match_parameter2 = 154 opcode = 328 parameter2 = entangle_immunity special = 1 STR_VAR insert = first END // clone immunity to entangle into set spell state
      END  
      PATCH_IF (haste_immunity > 0) BEGIN
        LPF CLONE_EFFECT INT_VAR multi_match = 1 match_opcode = 101 match_parameter2 = 16 opcode = 328 parameter2 = haste_immunity special = 1 STR_VAR insert = first END // clone immunity to haste into set spell state
      END  
      PATCH_IF (hold_immunity > 0) BEGIN
        LPF CLONE_EFFECT INT_VAR multi_match = 1 match_opcode = 101 match_parameter2 = 175 opcode = 328 parameter2 = hold_immunity special = 1 STR_VAR insert = first END // clone immunity to hold into set spell state
      END  
      PATCH_IF (slow_immunity > 0) BEGIN
        LPF CLONE_EFFECT INT_VAR multi_match = 1 match_opcode = 101 match_parameter2 = 40 opcode = 328 parameter2 = slow_immunity special = 1 STR_VAR insert = first END // clone immunity to slow into set spell state
      END  
      PATCH_IF (web_immunity > 0) BEGIN
        LPF CLONE_EFFECT INT_VAR multi_match = 1 match_opcode = 101 match_parameter2 = 157 opcode = 328 parameter2 = web_immunity special = 1 STR_VAR insert = first END // clone immunity to web into set spell state
        LPF CLONE_EFFECT INT_VAR match_opcode = 157 opcode = 324 parameter1 = web_immunity parameter2 = 110 timing = 0 duration = 0 resist_dispel = 0 savingthrow = 0 
          STR_VAR insert = above resource = EVAL ~%SOURCE_RES%~ END // web immune creatures block melee web effect
      END  
      BUT_ONLY 
  
  END 

(The second CLONE_EFFECT for web_immunity is because the item can web targets on hit, which will be covered next.) Lolth's Cruel Sting already has all of the normal Free Action effects from the Immunity Effect Macros in the overview, we're simply supplementing them with the new IMMUNITY spellstates. Effect order isn't quite as important here, so I've just added them to the top of the stack, but they would have worked just as well anywhere in the stack. They need to be paired as tightly as possible with the underlying effects that actually provide the protections, so I've only modified what I've had to (op, parameters, and the special field) and otherwise let them inherit the saves, timing, power, &c. of the effect being cloned.

For items which cause these kind of effects, ordering becomes more important. Let's look at the Monkey Paw of Discipline, which gets patched twice:

  ACTION_IF (confusion_immunity > 0) BEGIN 
  
    COPY_EXISTING ~u#clubmp.itm~ ~override~ // Monkey Paw of Discipline
                  ~u#swdbrc.itm~ ~override~ // Rage of Chaos
      LPF CLONE_EFFECT INT_VAR match_opcode = 128 opcode = 324 parameter1 = confusion_immunity parameter2 = 110 timing = 0 duration = 0 resist_dispel = 0 savingthrow = 0 STR_VAR insert = above resource = EVAL ~%SOURCE_RES%~ END
      BUT_ONLY
  
  END  
  
  // some other stuff
  
  ACTION_IF (panic_immunity > 0) BEGIN 
  
    COPY_EXISTING ~u#clubmp.itm~ ~override~ // Monkey Paw of Discipline
                  ~u#hfhrva.itm~ ~override~ // The Dire-Hammer Valorfoe
      LPF CLONE_EFFECT INT_VAR match_opcode =  24 opcode = 324 parameter1 = panic_immunity parameter2 = 110 timing = 0 duration = 0 resist_dispel = 0 savingthrow = 0 STR_VAR insert = first resource = EVAL ~%SOURCE_RES%~ END
      BUT_ONLY
  
  END  

The Monkey Paw causes fear on 15% of its melee hits, and confusion on 5%. Because 324s block all subsequent effects, the ordering becomes critical:

fx_monkey_paw.jpg

In this case I can get away with it because the two effects don't occur on an overlapping probability, and the 324s are inserted on the same ranges--e.g. the panic effects (effects 1-6) only occur on probabilities 0-14, and the 324 against it (effect 0) is also tied to that same 0-14 range, whereas confusion (and its 324) sit on the 95-99 range. You wouldn't want to make, say, a 324 vs. PANIC_IMMUNITY to run from 0-99 probability because then you could potentially cause a target that's immune to fear to erroneously block the confusion effects of the weapon. Note that in this case the code to insert the 324s preserves the probability values and also targets the first effect in the respective stacks: 324 for PANIC_IMMUNITY clones op24, the first of the panic effects (1-6) while the 324 for CONFUSION_IMMUNITY clones op128, the first of the confusion effects (effects 8-10). If this couldn't be rectified--if say, the Monkey Paw did both Panic and Confusion on all hits--you might have to manually split them into two separate spells and then apply them, using opcode 326, to creatures without the relevant spellstates.

The parameters of the 324 can be standardized to some degree. They're only needed for an instant to be effective, so a 0-duration, 0-timing effect is fine. Since they're a desirable effect for the target, they should also not be subject to MR or saves so set these all to 0 as well. Keep the underlying power value, however, so that it will work correctly for spell reflections.

The important takeaways here are that 1) a 324 must precede the effects it needs to block and 2) it will block everything that follows, if it applies. Let's look at another example where this is a bit more of an issue: Rage of Chaos can cause Chaos on its target and does bonus damage to lawful creatures:

  ACTION_IF (confusion_immunity > 0) BEGIN 
  
    COPY_EXISTING ~u#clubmp.itm~ ~override~ // Monkey Paw of Discipline
                  ~u#swdbrc.itm~ ~override~ // Rage of Chaos
      LPF CLONE_EFFECT INT_VAR match_opcode = 128 opcode = 324 parameter1 = confusion_immunity parameter2 = 110 timing = 0 duration = 0 resist_dispel = 0 savingthrow = 0 STR_VAR insert = above resource = EVAL ~%SOURCE_RES%~ END
      BUT_ONLY
  
  END   

Looking at the effect order:

fx_rage_of_chaos.jpg

Those two op177s provide the bonus damage vs. lawful alignments. In this case, they were originally below the confusion effects so they had to be moved to the top of the stack. (Since this is an item added by the mod, I simply made this change directly in the item file--if you're working with an existing resource, you could do some CLONE_ and DELETE_EFFECTs to accomplish this on the fly.) Had they not been moved, it would mean that the inserted 324 for CONFUSION_IMMUNITY could have blocked the bonus damage, introducing a bug.

Some final notes

Both the Monkey Paw and the Rage of Chaos have examples of edge cases not covered by the old method: The Monkey's Paw has a sound effect (op174) that would have otherwise slipped past a fear immunity, while Rage of Chaos has both sound (op175) and some visuals (op50) that wouldn't be blocked using the old, oBG2 method.

While the EE Fixpack has yet to hit its first release, you can go ahead and start planning for it--or be ready if another mod wants to use this implementation. While it's subject to change, the current list of immunity states being added by EEFP can be viewed and planned for.

Link to comment
On 5/18/2022 at 3:30 PM, CamDawg said:

If this couldn't be rectified--if say, the Monkey Paw did both Panic and Confusion on all hits--you might have to manually split them into two separate spells and then apply them, using opcode 326, to creatures without the relevant spellstates.

As an example, Improved Kitthix from Item Upgrade has to do this. Improved Kitthix's attack poisons and webs its target on every hit, so if we blindly apply the normal 324s then it's possible that the poison immunity could block the web, or the web immunity block the poison. So we shunt the web effects into a separate spell and apply it on hit with a 146:

fx_imp_kitthix.jpg

For EE games we add the normal poison 324s and, if web_immunity is available, turn that spellcast into a 326 targeted at creatures without web immunity (code from Item Upgrade) :

  COPY ~itemupgrade/itm/c2kita.itm~ ~override~
    PATCH_IF enhanced_edition BEGIN
      // add normal EE poison immunities
      LPF CLONE_EFFECT INT_VAR match_opcode = 25 opcode = 324 parameter2 = 55 timing = 0 duration = 0 resist_dispel = 0 savingthrow = 0 STR_VAR insert = above resource = EVAL ~%SOURCE_RES%~ END // golems/undead
      LPF CLONE_EFFECT INT_VAR match_opcode = 25 opcode = 324 parameter2 = 77 timing = 0 duration = 0 resist_dispel = 0 savingthrow = 0 STR_VAR insert = above resource = EVAL ~%SOURCE_RES%~ END // poison resist >= 100
      PATCH_IF (web_immunity > 0) BEGIN // if web_immunity, skip application of the web spell
        LPF ALTER_EFFECT INT_VAR match_opcode = 146 opcode = 326 parameter1 = web_immunity parameter2 = 111 END
      END  
    END

It's a simple shift: instead of applying the spell to everyone via op146, we use op326 to apply it specifically to creatures without (parameter2 set to 111) the web immunity spellstate (set in parameter1).

Edited by CamDawg
Link to comment
On 5/19/2022 at 12:30 AM, CamDawg said:

The important bits--the actual effects, portrait icons, and combat feedback--were blocked, so this was generally an acceptable tradeoff.

Well, it depends...

What if a mod uses a brand new (custom) Panic icon instead of the existing one? The old method cannot predict this kind of stuff...

On 5/19/2022 at 12:30 AM, CamDawg said:

Since they're a desirable effect for the target, they should also not be subject to MR, saves, or spell protections (power), so set these all to 0 as well. In fact, a non-zero power level can introduce e bug in that something like Spell Trap could eat a spell that the target is otherwise immune against.

Actually, `power` should be left as is (you know, in case of Spell Turning, op318/324 effects should be reflected back...)

Link to comment
1 hour ago, Luke said:

What if a mod uses a brand new (custom) Panic icon instead of the existing one? The old method cannot predict this kind of stuff...

The new method definitely does this better. That being said, if a mod introduces a new icon and doesn't update the spells and items that should protect against it, that's on the mod.

1 hour ago, Luke said:

Actually, `power` should be left as is (you know, in case of Spell Turning, op318/324 effects should be reflected back...)

I don't think this is as clear-cut. I like reflecting spells, but on the other hand I don't want spells to which I'm otherwise immune to burn through, say, my Spell Trap. (And before anyone says it, yes, there are times when it would be beneficial to let otherwise ineffective spells hit the Spell Trap too.) In a tabletop session, this kind of flexibility is possible--since we don't have that here, we have to pick one or the other.

Personally I'm willing to make that tradeoff so that my protections don't get wasted on stuff to which I'm already immune. I honestly have no idea if I'm in a minority or majority on this opinion, and I think it's something worth more discussion.

Link to comment
41 minutes ago, CamDawg said:

I don't think this is as clear-cut. I like reflecting spells, but on the other hand I don't want spells to which I'm otherwise immune to burn through, say, my Spell Trap. (And before anyone says it, yes, there are times when it would be beneficial to let otherwise ineffective spells hit the Spell Trap too.) In a tabletop session, this kind of flexibility is possible--since we don't have that here, we have to pick one or the other.

Personally I'm willing to make that tradeoff so that my protections don't get wasted on stuff to which I'm already immune. I honestly have no idea if I'm in a minority or majority on this opinion, and I think it's something worth more discussion.

The issue isn't about when you are immune, but when the original caster should be immune.

If those effects don't get reflected, then they will not protect the original caster when they should.

Link to comment

 

15 hours ago, CamDawg said:

The new method definitely does this better. That being said, if a mod introduces a new icon and doesn't update the spells and items that should protect against it, that's on the mod.

Yes, but then install order comes into play.

In fact, such a mod should be installed after mods that add spells / items granting protection against Panic... But there is no way to know how many there are...

Thanks to this new method, install order is no longer relevant...

15 hours ago, kjeron said:

The issue isn't about when you are immune, but when the original caster should be immune.

If those effects don't get reflected, then they will not protect the original caster when they should.

Exactly (I should have clarified it better...)

As a result, you @CamDawg might want to edit your guide accordingly...

Link to comment
On 5/19/2022 at 12:30 AM, CamDawg said:

As a fallback, items or spells that provide immunities would still provide the normal suite of effects you'd see from the BG2 Fixpack immunity batches mentioned in the overview--blocking the opcode, associated portrait icons, combat feedback, and the like.

(also calling @DavidW)

What if I told you this is actually a problem and should be removed on EE games...?

That is to say: what if certain creatures should be immune to, say, all confusion effects except if coming from a specific spell/attack (or from some specific spells/attacks)?

As you all know, we have two Panic opcodes, two Hold opcodes, two Charm opcodes, etc... but we don't have two Confusion opcodes! Additionally, op337 does not work with a limited timing mode (the two Bigby spells use this trick to force the targeted creature to fall down, but the problem is that the immunity is not restored)... plus it cannot remove effects applied with timing mode 9...

Having said that, thanks to the new (splstate) method, we no longer need to rely upon op101 (and its accompanying effects op267, op296, op169, etc...)

Real case study: CLERIC_FALSE_DAWN ("sppr609.spl") is supposed to confuse GENERAL=UNDEAD creatures (as per its description). Now, since most (all?) undead are immune to Confusion (plus icon, visual effects, etc...), this spell is not working as expected. But you see...? If undead were not immune to Confusion (plus its accompanying effects) and CLERIC_FALSE_DAWN did not check for CONFUSION_IMMUNITY, they would be immune to all Confusion sources but this one (as intended).

To sum up: if an undead is immune to Confusion, @DavidW's code should

  1. remove op101 along with all its associated effects (again, op169, op267, op296, etc...)
  2. flag it as CONFUSION_IMMUNITY (via op328)
  3. add the 324 check for CONFUSION_IMMUNITY to all spl/itm files that apply Confusion (op128), while skipping special cases like the aforementioned one

As already said, you might want to do that for all opcodes that are not in pairs... On reflection, you might want to do that for all opcodes indiscriminately... I mean, if I used op241 (Charm 2) to bypass immunity (op101) to op5 (Charm 1), the targeted creature would certainly be charmed (since nobody is supposed to be immune to the alternate opcode), but the Charm Icon / Visual effect / sound / etc... would still be blocked...

Thoughts...?

Addendum: getting rid of op101 would also allow Earthquake-like, knockdown (Dragon Wing Buffet – "spin695.spl") spells/attacks to bypass / ignore Chaotic Commands and the like (these spells are supposed to block only true Sleep / Unconsciousness effects, not also Earthquake and knockdown attacks...)

Link to comment

I certainly see the appeal of this; the problem is that it would wreak absolute havoc on mods. Any newly-added effects that, e.g., confuse or hold will no longer be blocked.  One could always just reimplement 324-based immunity in some late-installed mod (SCS will probably do this as of the next version); still, it's not great to have a situation where the fixpack breaks a huge fraction of extant mods and that break can only be fixed by editing the mod (in a way that requires WEIDU code and can't be done in NI, if compatibility with oBG2 is to be maintained) or by installing some third mod. On balance (and seeing the case for the contrary) I'd rather not do that in something that's supposed to be a safe must-install-first mod. 

(EDIT: I got the details of this wrong first time, though I think the general point is still right.)

Link to comment
10 hours ago, Luke said:

Addendum: getting rid of op101 would also allow Earthquake-like, knockdown (Dragon Wing Buffet – "spin695.spl") spells/attacks to bypass / ignore Chaotic Commands and the like (these spells are supposed to block only true Sleep / Unconsciousness effects, not also Earthquake and knockdown attacks...)

As DavidW said... replacing 101/206 on cre immunity items with 324 in spell or item inflicting the effect needs to come absolutely last in the mod install order or it will break things.

My old school way of implementing this was to use short duration opcode 283 which bypasses 101 immunity to other opcodes; thus you can have physical knockdowns through opcode 39 as a separate EFF applied through 283 on creatures normally immune to "sleep" etc.

Link to comment
6 hours ago, polytope said:

As DavidW said... replacing 101/206 on cre immunity items with 324 in spell or item inflicting the effect needs to come absolutely last in the mod install order or it will break things.

15 hours ago, DavidW said:

I certainly see the appeal of this; the problem is that it would wreak absolute havoc on mods. Any newly-added effects that, e.g., confuse or hold will no longer be blocked

Yes, sure, mods will need to adapt to the new system, otherwise it's a mess... Also, having such a tweak last in the mod install order might be a problem (it might be problematic to tell if an op39 effect is, say, Unconsciousness or Knockdown, especially considering mod-added assets...)

6 hours ago, polytope said:

My old school way of implementing this was to use short duration opcode 283 which bypasses 101 immunity to other opcodes; thus you can have physical knockdowns through opcode 39 as a separate EFF applied through 283 on creatures normally immune to "sleep" etc.

This is interesting, I did not know it, and it can indeed solve this issue... What do you mean exactly by "short duration"...? I mean, EFF files applied through op177/283 ignore the Duration field (i.e., they use whatever Duration you set on the op177/283...) Could you please attach here how you would code, say, SPIN695.SPL to force the creature to fall down...? Also, the fact that op283 can be removed by op26 (Remove Curse) is a problem, right...? So maybe we should also add an immunity to op26...?

For @Bubb: apparently, EFF files applied by op283 can bypass / ignore op101. Bug or Feature...? Something else to know about it...?

Link to comment
2 hours ago, Luke said:

Could you please attach here how you would code, say, SPIN695.SPL to force the creature to fall down...? Also, the fact that op283 can be removed by op26 (Remove Curse) is a problem, right...? So maybe we should also add an immunity to op26...?

I'm not positive it works on Enhanced Edition, I don't have EE installed on the device I'm currently using, but it certainly worked on the original engine. Yes, if it's not a very short duration effect like knockdown from wing buffet can tack in a 101 vs remove curse but I'd prefer not to use this trick for long duration effects (what if the player actually does suffer a curse they need removing in the meanwhile?).

I simply create an EFF file; opcode 39, no save/MR check/duration field blank (all will be inherited from the feature block of the spell), timing mode 0 target type 2 (I'm less certain about those two) name it A^KNCKDW, replace the sleep effect in the spell to be modified with 283 and resource is A^KNCKDWN.

If you mean, a Weidu macro to do this stuff, I don't have one lying around, it wouldn't be hard to make though.

Link to comment
56 minutes ago, polytope said:

I simply create an EFF file; opcode 39, no save/MR check/duration field blank (all will be inherited from the feature block of the spell), timing mode 0 target type 2 (I'm less certain about those two) name it A^KNCKDW, replace the sleep effect in the spell to be modified with 283 and resource is A^KNCKDWN.

So I understand: so if this is supposed to be a 6-second knockdown, then the op283 effect would have a 6-second duration? The target would be "cursed" to sleep for 6 seconds, but would not have any lingering "curse" effects? And it wouldn't interfere with any other op283 effects?

Cool.

Link to comment
3 hours ago, polytope said:

I'm not positive it works on Enhanced Edition, I don't have EE installed on the device I'm currently using, but it certainly worked on the original engine.

Apparently, it works fine on EEs too...

3 hours ago, polytope said:

timing mode 0 target type 2 (I'm less certain about those two)

Also these two values will be inherited from the feature block of the spell, you can safely leave them at 0...

3 hours ago, polytope said:

(what if the player actually does suffer a curse they need removing in the meanwhile?).

Yeah, that would be a problem... Maybe @kjeron knows a workaround...? I'm not positive...

It'd be much much easier if EE mods adapted to the new splstate system, there would be lots of benefits...

Edited by Luke
Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...