mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
DNA splicers
This commit is contained in:
@@ -66,6 +66,8 @@ class PictureWindow < SpriteWindow_Base
|
||||
setBitmap(pathOrBitmap)
|
||||
end
|
||||
|
||||
def picture; @_iconbitmap; end
|
||||
|
||||
def dispose
|
||||
clearBitmaps()
|
||||
super
|
||||
|
||||
@@ -18,6 +18,17 @@ class AnimatedBitmap
|
||||
end
|
||||
end
|
||||
|
||||
def pbSetColor(r = 0, g = 0, b = 0, a = 255)
|
||||
for i in 0..@bitmap.bitmap.width
|
||||
for j in 0..@bitmap.bitmap.height
|
||||
if @bitmap.bitmap.get_pixel(i, j).alpha != 0
|
||||
color = Color.new(r, g, b, a)
|
||||
@bitmap.bitmap.set_pixel(i, j, color)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def [](index)
|
||||
; @bitmap[index];
|
||||
end
|
||||
@@ -82,7 +93,6 @@ class AnimatedBitmap
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
|
||||
@@ -83,7 +83,7 @@ module PokeBattle_BattleCommon
|
||||
if itemName.starts_with_vowel?
|
||||
pbDisplay(_INTL("{1} threw an {2}!",pbPlayer.name,itemName))
|
||||
else
|
||||
pbDisplay(_INTL("{1} threw a {2}!",pbPlayer.name,itemName))
|
||||
pbDisplay(_INTL("{1} vcthrew a {2}!",pbPlayer.name,itemName))
|
||||
end
|
||||
pbDisplay(_INTL("But there was no target..."))
|
||||
return
|
||||
|
||||
@@ -16,11 +16,13 @@ module ItemHandlers
|
||||
return UseText[item] != nil
|
||||
end
|
||||
|
||||
def self.hasOutHandler(item) # Shows "Use" option in Bag
|
||||
def self.hasOutHandler(item)
|
||||
# Shows "Use" option in Bag
|
||||
return UseFromBag[item] != nil || UseInField[item] != nil || UseOnPokemon[item] != nil
|
||||
end
|
||||
|
||||
def self.hasUseInFieldHandler(item) # Shows "Register" option in Bag
|
||||
def self.hasUseInFieldHandler(item)
|
||||
# Shows "Register" option in Bag
|
||||
return UseInField[item] != nil
|
||||
end
|
||||
|
||||
@@ -102,8 +104,6 @@ module ItemHandlers
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbCanRegisterItem?(item)
|
||||
return ItemHandlers.hasUseInFieldHandler(item)
|
||||
end
|
||||
@@ -112,8 +112,6 @@ def pbCanUseOnPokemon?(item)
|
||||
return ItemHandlers.hasUseOnPokemon(item) || GameData::Item.get(item).is_machine?
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Change a Pokémon's level
|
||||
#===============================================================================
|
||||
@@ -434,6 +432,52 @@ def pbLearnMove(pkmn,move,ignoreifknown=false,bymachine=false,&block)
|
||||
end
|
||||
end
|
||||
|
||||
def pbLearnMove(pkmn, move, ignoreifknown = false, bymachine = false, fast = false, &block)
|
||||
return false if !pkmn
|
||||
move = GameData::Move.get(move).id
|
||||
if pkmn.egg? && !$DEBUG
|
||||
pbMessage(_INTL("Eggs can't be taught any moves."), &block)
|
||||
return false
|
||||
end
|
||||
if pkmn.shadowPokemon?
|
||||
pbMessage(_INTL("Shadow Pokémon can't be taught any moves."), &block)
|
||||
return false
|
||||
end
|
||||
pkmnname = pkmn.name
|
||||
movename = GameData::Move.get(move).name
|
||||
if pkmn.hasMove?(move)
|
||||
pbMessage(_INTL("{1} already knows {2}.", pkmnname, movename), &block) if !ignoreifknown
|
||||
return false
|
||||
end
|
||||
if pkmn.numMoves < Pokemon::MAX_MOVES
|
||||
pkmn.learn_move(move)
|
||||
pbMessage(_INTL("\\se[]{1} learned {2}!\\se[Pkmn move learnt]", pkmnname, movename), &block)
|
||||
return true
|
||||
end
|
||||
loop do
|
||||
pbMessage(_INTL("{1} wants to learn {2}, but it already knows {3} moves.\1",
|
||||
pkmnname, movename, pkmn.numMoves.to_word), &block) if !bymachine && !fast
|
||||
pbMessage(_INTL("Please choose a move that will be replaced with {1}.", movename), &block)
|
||||
forgetmove = pbForgetMove(pkmn, move)
|
||||
if forgetmove >= 0
|
||||
oldmovename = pkmn.moves[forgetmove].name
|
||||
oldmovepp = pkmn.moves[forgetmove].pp
|
||||
pkmn.moves[forgetmove] = Pokemon::Move.new(move) # Replaces current/total PP
|
||||
if bymachine && Settings::TAUGHT_MACHINES_KEEP_OLD_PP
|
||||
pkmn.moves[forgetmove].pp = [oldmovepp, pkmn.moves[forgetmove].total_pp].min
|
||||
end
|
||||
pbMessage(_INTL("1, 2, and...\\wt[16] ...\\wt[16] ... Ta-da!\\se[Battle ball drop]\1"), &block) if !fast
|
||||
pbMessage(_INTL("{1} forgot how to use {2}.\\nAnd...\1", pkmnname, oldmovename), &block) if !fast
|
||||
pbMessage(_INTL("\\se[]{1} learned {2}!\\se[Pkmn move learnt]", pkmnname, movename), &block)
|
||||
pkmn.changeHappiness("machine") if bymachine
|
||||
return true
|
||||
elsif pbConfirmMessage(_INTL("Give up on learning {1}?", movename), &block)
|
||||
pbMessage(_INTL("{1} did not learn {2}.", pkmnname, movename), &block)
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbForgetMove(pkmn, moveToLearn)
|
||||
ret = -1
|
||||
pbFadeOutIn {
|
||||
@@ -511,9 +555,12 @@ def pbUseItem(bag,item,bagscene=nil)
|
||||
elsif useType == 2 # Item is usable from Bag
|
||||
intret = ItemHandlers.triggerUseFromBag(item)
|
||||
case intret
|
||||
when 0 then return 0
|
||||
when 1 then return 1 # Item used
|
||||
when 2 then return 2 # Item used, end screen
|
||||
when 0 then
|
||||
return 0
|
||||
when 1 then
|
||||
return 1 # Item used
|
||||
when 2 then
|
||||
return 2 # Item used, end screen
|
||||
when 3 # Item used, consume item
|
||||
bag.pbDeleteItem(item)
|
||||
return 1
|
||||
|
||||
@@ -936,58 +936,6 @@ ItemHandlers::UseOnPokemon.add(:PRISONBOTTLE,proc { |item,pkmn,scene|
|
||||
next true
|
||||
})
|
||||
|
||||
ItemHandlers::UseOnPokemon.add(:DNASPLICERS,proc { |item,pkmn,scene|
|
||||
if !pkmn.isSpecies?(:KYUREM)
|
||||
scene.pbDisplay(_INTL("It had no effect."))
|
||||
next false
|
||||
end
|
||||
if pkmn.fainted?
|
||||
scene.pbDisplay(_INTL("This can't be used on the fainted Pokémon."))
|
||||
next false
|
||||
end
|
||||
# Fusing
|
||||
if pkmn.fused.nil?
|
||||
chosen = scene.pbChoosePokemon(_INTL("Fuse with which Pokémon?"))
|
||||
next false if chosen<0
|
||||
poke2 = $Trainer.party[chosen]
|
||||
if pkmn==poke2
|
||||
scene.pbDisplay(_INTL("It cannot be fused with itself."))
|
||||
next false
|
||||
elsif poke2.egg?
|
||||
scene.pbDisplay(_INTL("It cannot be fused with an Egg."))
|
||||
next false
|
||||
elsif poke2.fainted?
|
||||
scene.pbDisplay(_INTL("It cannot be fused with that fainted Pokémon."))
|
||||
next false
|
||||
elsif !poke2.isSpecies?(:RESHIRAM) &&
|
||||
!poke2.isSpecies?(:ZEKROM)
|
||||
scene.pbDisplay(_INTL("It cannot be fused with that Pokémon."))
|
||||
next false
|
||||
end
|
||||
newForm = 0
|
||||
newForm = 1 if poke2.isSpecies?(:RESHIRAM)
|
||||
newForm = 2 if poke2.isSpecies?(:ZEKROM)
|
||||
pkmn.setForm(newForm) {
|
||||
pkmn.fused = poke2
|
||||
$Trainer.remove_pokemon_at_index(chosen)
|
||||
scene.pbHardRefresh
|
||||
scene.pbDisplay(_INTL("{1} changed Forme!",pkmn.name))
|
||||
}
|
||||
next true
|
||||
end
|
||||
# Unfusing
|
||||
if $Trainer.party_full?
|
||||
scene.pbDisplay(_INTL("You have no room to separate the Pokémon."))
|
||||
next false
|
||||
end
|
||||
pkmn.setForm(0) {
|
||||
$Trainer.party[$Trainer.party.length] = pkmn.fused
|
||||
pkmn.fused = nil
|
||||
scene.pbHardRefresh
|
||||
scene.pbDisplay(_INTL("{1} changed Forme!",pkmn.name))
|
||||
}
|
||||
next true
|
||||
})
|
||||
|
||||
ItemHandlers::UseOnPokemon.add(:NSOLARIZER,proc { |item,pkmn,scene|
|
||||
if !pkmn.isSpecies?(:NECROZMA) || pkmn.form == 2
|
||||
|
||||
@@ -54,6 +54,14 @@ class PokemonSprite < SpriteWrapper
|
||||
changeOrigin
|
||||
end
|
||||
|
||||
def setPokemonBitmapFromId(id,back=false)
|
||||
@_iconbitmap.dispose if @_iconbitmap
|
||||
@_iconbitmap = GameData::Species.sprite_bitmap_from_pokemon_id(id, back)
|
||||
self.bitmap = (@_iconbitmap) ? @_iconbitmap.bitmap : nil
|
||||
self.color = Color.new(0,0,0,0)
|
||||
changeOrigin
|
||||
end
|
||||
|
||||
def setPokemonBitmapSpecies(pokemon,species,back=false)
|
||||
@_iconbitmap.dispose if @_iconbitmap
|
||||
@_iconbitmap = (pokemon) ? GameData::Species.sprite_bitmap_from_pokemon(pokemon, back, species) : nil
|
||||
|
||||
@@ -12,6 +12,15 @@ module GameData
|
||||
return ret
|
||||
end
|
||||
|
||||
def self.sprite_bitmap_from_pokemon_id(id, back = false)
|
||||
if back
|
||||
ret = self.back_sprite_bitmap(id)
|
||||
else
|
||||
ret = self.front_sprite_bitmap(id)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def self.front_sprite_bitmap(dex_number)
|
||||
filename = self.sprite_filename(dex_number)
|
||||
return (filename) ? AnimatedBitmap.new(filename) : nil
|
||||
|
||||
1648
Data/Scripts/050_AddOns/New Items effects.rb
Normal file
1648
Data/Scripts/050_AddOns/New Items effects.rb
Normal file
File diff suppressed because it is too large
Load Diff
@@ -58,8 +58,6 @@ class PBFusion
|
||||
]
|
||||
end
|
||||
|
||||
|
||||
|
||||
class SpriteMetafile
|
||||
VIEWPORT = 0
|
||||
TONE = 1
|
||||
@@ -279,8 +277,6 @@ class SpriteMetafile
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class SpriteMetafilePlayer
|
||||
def initialize(metafile, sprite = nil)
|
||||
@metafile = metafile
|
||||
@@ -353,8 +349,6 @@ class SpriteMetafilePlayer
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbSaveSpriteState(sprite)
|
||||
state = []
|
||||
return state if !sprite || sprite.disposed?
|
||||
@@ -412,12 +406,11 @@ def pbRestoreSpriteStateAndBitmap(sprite,state)
|
||||
return state
|
||||
end
|
||||
|
||||
|
||||
|
||||
#####################
|
||||
|
||||
class PokemonFusionScene
|
||||
private
|
||||
|
||||
def pbGenerateMetafiles(s1x, s1y, s2x, s2y, s3x, s3y, sxx, s3xx)
|
||||
sprite = SpriteMetafile.new
|
||||
sprite3 = SpriteMetafile.new
|
||||
@@ -427,7 +420,6 @@ class PokemonFusionScene
|
||||
sprite3.opacity = 255
|
||||
sprite2.opacity = 0
|
||||
|
||||
|
||||
sprite.ox = s1x
|
||||
sprite.oy = s1y
|
||||
sprite2.ox = s2x
|
||||
@@ -435,7 +427,6 @@ class PokemonFusionScene
|
||||
sprite3.ox = s3x
|
||||
sprite3.oy = s3y
|
||||
|
||||
|
||||
sprite.x = sxx
|
||||
sprite3.x = s3xx
|
||||
|
||||
@@ -456,8 +447,6 @@ class PokemonFusionScene
|
||||
sprite3.color.alpha = j * 10
|
||||
sprite3.color = sprite3.color
|
||||
|
||||
|
||||
|
||||
sprite2.color = sprite.color
|
||||
sprite.update
|
||||
sprite3.update
|
||||
@@ -472,7 +461,6 @@ class PokemonFusionScene
|
||||
sprite3.angle += anglechange
|
||||
sprite3.angle %= 360
|
||||
|
||||
|
||||
anglechange += 5 if j % 2 == 0
|
||||
if j >= sevenseconds - 50
|
||||
sprite2.angle = sprite.angle
|
||||
@@ -506,13 +494,10 @@ class PokemonFusionScene
|
||||
sprite3.opacity -= 6
|
||||
end
|
||||
|
||||
|
||||
|
||||
sprite3.update
|
||||
sprite.update
|
||||
sprite2.update
|
||||
|
||||
|
||||
end
|
||||
for j in 0...26
|
||||
sprite2.color.red = 30
|
||||
@@ -543,15 +528,17 @@ class PokemonFusionScene
|
||||
addBackgroundOrColoredPlane(@sprites, "background", "evolutionbg",
|
||||
Color.new(248, 248, 248), @viewport)
|
||||
|
||||
poke1_number = GameData::Species.get(@pokemon1.species).id_number
|
||||
poke2_number = GameData::Species.get(@pokemon2.species).id_number
|
||||
|
||||
rsprite1 = PokemonSprite.new(@viewport)
|
||||
rsprite2 = PokemonSprite.new(@viewport)
|
||||
rsprite3 = PokemonSprite.new(@viewport)
|
||||
|
||||
rsprite1.setPokemonBitmap(@pokemon1,false)
|
||||
rsprite3.setPokemonBitmap(@pokemon2,false)
|
||||
rsprite1.setPokemonBitmapFromId(poke1_number, false)
|
||||
rsprite3.setPokemonBitmapFromId(poke2_number, false)
|
||||
|
||||
rsprite2.setPokemonBitmapSpecies(@pokemon1,@newspecies,false)
|
||||
rsprite2.setPokemonBitmapFromId(@newspecies, false)
|
||||
|
||||
rsprite1.ox = rsprite1.bitmap.width / 2
|
||||
rsprite1.oy = rsprite1.bitmap.height / 2
|
||||
@@ -562,8 +549,6 @@ class PokemonFusionScene
|
||||
rsprite2.ox = rsprite2.bitmap.width / 2
|
||||
rsprite2.oy = rsprite2.bitmap.height / 2
|
||||
|
||||
|
||||
|
||||
rsprite2.x = Graphics.width / 2
|
||||
rsprite1.y = (Graphics.height - 96) / 2
|
||||
rsprite3.y = (Graphics.height - 96) / 2
|
||||
@@ -571,7 +556,6 @@ class PokemonFusionScene
|
||||
rsprite1.x = (Graphics.width / 2) - 100
|
||||
rsprite3.x = (Graphics.width / 2) + 100
|
||||
|
||||
|
||||
rsprite2.y = (Graphics.height - 96) / 2
|
||||
rsprite2.opacity = 0
|
||||
@sprites["rsprite1"] = rsprite1
|
||||
@@ -614,11 +598,12 @@ class PokemonFusionScene
|
||||
end
|
||||
|
||||
def averageFusionIvs()
|
||||
for i in 0..@pokemon1.iv.length-1
|
||||
poke1Iv = @pokemon1.iv[i]
|
||||
poke2Iv = @pokemon2.iv[i]
|
||||
@pokemon1.iv[i] = ((poke1Iv+poke2Iv)/2).floor
|
||||
end
|
||||
return
|
||||
# for i in 0..@pokemon1.iv.length-1
|
||||
# poke1Iv = @pokemon1.iv[i]
|
||||
# poke2Iv = @pokemon2.iv[i]
|
||||
# @pokemon1.iv[i] = ((poke1Iv+poke2Iv)/2).floor
|
||||
# end
|
||||
end
|
||||
|
||||
#unused. was meant for super splicers, but too broken
|
||||
@@ -644,7 +629,6 @@ class PokemonFusionScene
|
||||
metaplayer2 = SpriteMetafilePlayer.new(@metafile2, @sprites["rsprite2"])
|
||||
metaplayer3 = SpriteMetafilePlayer.new(@metafile3, @sprites["rsprite3"])
|
||||
|
||||
|
||||
metaplayer1.play
|
||||
metaplayer2.play
|
||||
metaplayer3.play
|
||||
@@ -654,8 +638,6 @@ class PokemonFusionScene
|
||||
Kernel.pbMessageDisplay(@sprites["msgwindow"],
|
||||
_INTL("The Pokémon are being fused!", @pokemon1.name))
|
||||
|
||||
|
||||
|
||||
Kernel.pbMessageWaitForInput(@sprites["msgwindow"], 100, true)
|
||||
pbPlayDecisionSE()
|
||||
oldstate = pbSaveSpriteState(@sprites["rsprite1"])
|
||||
@@ -693,27 +675,28 @@ class PokemonFusionScene
|
||||
Graphics.update
|
||||
end
|
||||
pbMEPlay("Voltorb Flip Win")
|
||||
newspeciesname=PBSpecies.getName(@newspecies)
|
||||
oldspeciesname=PBSpecies.getName(@pokemon1.species)
|
||||
newSpecies = GameData::Species.get(@newspecies)
|
||||
newspeciesname = newSpecies.real_name
|
||||
oldspeciesname = GameData::Species.get(@pokemon1.species).real_name
|
||||
|
||||
Kernel.pbMessageDisplay(@sprites["msgwindow"],
|
||||
_INTL("\\se[]Congratulations! Your Pokémon were fused into {2}!\\wt[80]", @pokemon1.name, newspeciesname))
|
||||
|
||||
averageFusionIvs()
|
||||
#add to pokedex
|
||||
if ! $Trainer.owned[@newspecies]
|
||||
$Trainer.seen[@newspecies]=true
|
||||
$Trainer.owned[@newspecies]=true
|
||||
pbSeenForm(@pokemon)
|
||||
if !$Trainer.pokedex.owned?(newSpecies)
|
||||
$Trainer.pokedex.set_seen(newSpecies)
|
||||
$Trainer.pokedex.set_owned(newSpecies)
|
||||
Kernel.pbMessageDisplay(@sprites["msgwindow"],
|
||||
_INTL("{1}'s data was added to the Pokédex", newspeciesname))
|
||||
@scene.pbShowPokedex(@newspecies)
|
||||
#@scene.pbShowPokedex(@newspecies)
|
||||
end
|
||||
#first check if hidden ability
|
||||
hiddenAbility1 = @pokemon1.ability == @pokemon1.getAbilityList[0][-1]
|
||||
hiddenAbility2 = @pokemon2.ability == @pokemon2.getAbilityList[0][-1]
|
||||
|
||||
#change species
|
||||
@pokemon1.species=@newspecies
|
||||
@pokemon1.species = newSpecies
|
||||
|
||||
#Check moves for new species
|
||||
movelist = @pokemon1.getMoveList
|
||||
@@ -729,30 +712,28 @@ class PokemonFusionScene
|
||||
end
|
||||
|
||||
#make it untraded, pour qu'on puisse le unfused après, même si un des 2 était traded
|
||||
@pokemon1.obtainMode = 0
|
||||
@pokemon1.obtain_method = 0
|
||||
|
||||
@pokemon1.setAbility(pbChooseAbility(@pokemon1,hiddenAbility1,hiddenAbility2))
|
||||
@pokemon1.ability = pbChooseAbility(@pokemon1, hiddenAbility1, hiddenAbility2)
|
||||
if superSplicer
|
||||
@pokemon1.setNature(pbChooseNature(@pokemon1.nature,@pokemon2.nature))
|
||||
@pokemon1.nature = pbChooseNature(@pokemon1.nature, @pokemon2.nature)
|
||||
end
|
||||
|
||||
movelist = @pokemon2.moves
|
||||
for k in movelist
|
||||
if k.id != 0
|
||||
pbLearnMove(@pokemon1,k.id,true,false,true) if !noMoves
|
||||
pbLearnMove(@pokemon1, k.id, true, false,true) if !noMoves #todo: learn moves faster
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
pbSEPlay("Voltorb Flip Point")
|
||||
|
||||
@pokemon1.firstmoves=[]
|
||||
#@pokemon1.firstmoves = []
|
||||
@pokemon1.name = newspeciesname if @pokemon1.name == oldspeciesname
|
||||
|
||||
@pokemon1.level = setPokemonLevel(@pokemon1.level, @pokemon2.level, superSplicer)
|
||||
@pokemon1.calcStats
|
||||
@pokemon1.obtainMode = 0
|
||||
@pokemon1.calc_stats
|
||||
@pokemon1.obtain_method = 0
|
||||
|
||||
end
|
||||
end
|
||||
@@ -785,9 +766,6 @@ def pbShowPokedex(species)
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def pbChooseAbility(poke, hidden1 = false, hidden2 = false)
|
||||
abilityList = poke.getAbilityList
|
||||
#pas sur de l'ordre pour les hidden (3 et 4) peut-être a inverser
|
||||
@@ -797,17 +775,19 @@ def pbChooseAbility(poke,hidden1=false,hidden2=false)
|
||||
#4. hidden du poke 1
|
||||
#5. hidden du poke2
|
||||
|
||||
abID1 = hidden1 ? abilityList[4][0] : abilityList[0][0]
|
||||
abID2 = hidden2 ? abilityList[5][0] : abilityList[1][0]
|
||||
|
||||
abID1 = hidden1 ? abilityList[0][4] : abilityList[0][0]
|
||||
abID2 = hidden2 ? abilityList[0][5] : abilityList[0][1]
|
||||
|
||||
if (Kernel.pbMessage("Choose an ability.",[_INTL("{1}",PBAbilities.getName(abID1)),_INTL("{1}",PBAbilities.getName(abID2))],2))==0
|
||||
ability1_name = GameData::Ability.get(abID1).name
|
||||
ability2_name = GameData::Ability.get(abID2).name
|
||||
|
||||
if (Kernel.pbMessage("Choose an ability.", [_INTL("{1}", ability1_name), _INTL("{1}", ability2_name)], 2)) == 0
|
||||
return hidden1 ? 4 : 0
|
||||
end
|
||||
return hidden2 ? 5 : 1
|
||||
end
|
||||
|
||||
|
||||
#pas au point. renvoie tjrs la mm nature
|
||||
def pbChooseNature(species1, species2)
|
||||
nature1 = PBNatures.getName(species1)
|
||||
@@ -819,8 +799,6 @@ def pbChooseNature(species1,species2)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#EDITED FOR GEN2
|
||||
def fixEvolutionOverflow(retB, retH, oldSpecies)
|
||||
#raise Exception.new("retB: " + retB.to_s + " retH: " + retH.to_s)
|
||||
|
||||
Reference in New Issue
Block a user