Paste #14211: Untitled Paste

Date: 2015/03/04 05:32:17 UTC-08:00
Type: Denizen Script

View Raw Paste Download This Paste
Copy Link


# Procedural mob spawning/summoning (pms)
pmsMainWrapper:
  type: world

  events:
    on server start:
      - flag global pmsWorldName:Kratanien
      - flag global pmsMaxDifficulty:100
      - flag global pmsMobHP:!
      - flag global pmsMobHP:|:10|200
      - flag global pmsMobSpeed:!
      - flag global pmsMobSpeed:|:0.23|0.4
      - flag global pmsAttackDamage:!
      - flag global pmsAttackDamage:|:1.5|7
      - flag global pmsKnockbackResistance:!
      - flag global pmsKnockbackResistance:|:-0.5|1

      # TODO add gaussRand for difficulty

      - flag global pmsPlayerHeadProbability:!
      - flag global pmsPlayerHeadProbability:|:0|0.3

      # The probability of each location to spawn a normal mob. Bosses will always spawn.
      # E.g: You provide 10 locations to spawnTreasureMobs. Each of the normal mobs will have this probability of spawning.
      # This logic helps to randomize the spawn locations, thus players cannot anticipate where the mobs will spawn.
      - flag global pmsSpawnProbability:0.66

      # Doesn't work correctly right now because Minecraft ties the durability of an item
      # to the DropChance. If DropChance is between 0 and 1, it will automatically generate
      # a random durability for the dropped item, regardless of the actual setting.
      # If however the DropChance is > 1, the durability will be the set number, but the item will always drop.
      # I'm leaving this in as it might chance in the future (now is: Minecraft 1.8.1, 03.02.2015)
      - flag global pmsItemDamaged:!
      - flag global pmsItemDamaged:|:0.2|0.9

      - flag global pmsDropRate:!
      - flag global pmsDropRate:|:0.2|0.05

      # Normal mobs will have 0.5 * boss difficulty
      - flag global pmsMobToBossDifficulty:0.5

      - flag global pmsBabyPercentage:!
      - flag global pmsBabyPercentage:|:0.3|-1

      # Mobs with min level will have 10% (=0.1) chance of having an item equipped.
      # Mobs with max level will have 90% (=0.9) chance of having an item equipped.
      - flag global pmsEquipRange:!
      - flag global pmsEquipRange:|:0.3|1

      # In percent. E.g.: 0 = Five players have same difficulty as one player.
      # 15 = Difficulty is 130% for three players (adding 15% difficulty per additional player)
      # One player will always have difficulty 100% scaled to <fl@pmsMaxDifficulty>
      - flag global pmsDifficultyIncreasePerPlayer:15
      - flag global pmsWeapons:!
      - flag global pmsWeapons:|:sword_1|sword_2|sword_3|sword_4|sword_5|sword_6|sword_7|sword_8|sword_9|sword_10|sword_11|sword_12|sword_13|sword_14|sword_15
      - flag global pmsBows:!
      - flag global pmsBows:|:bow_1|bow_2|bow_3|bow_4|bow_5|bow_6
      - flag global pmsHelmets:!
      - flag global pmsHelmets:|:helmet_1|helmet_2|helmet_3|helmet_4|helmet_5|helmet_6|helmet_7|helmet_8|helmet_9|helmet_10|helmet_11|helmet_12|helmet_13|helmet_14|helmet_15|helmet_16|helmet_17
      - flag global pmsChestplates:!
      - flag global pmsChestplates:|:chestplate_1|chestplate_2|chestplate_3|chestplate_4|chestplate_5|chestplate_6|chestplate_7|chestplate_8|chestplate_9|chestplate_10|chestplate_11|chestplate_12|chestplate_13|chestplate_14|chestplate_15
      - flag global pmsLeggings:!
      - flag global pmsLeggings:|:leggings_1|leggings_2|leggings_3|leggings_4|leggings_5|leggings_6|leggings_7|leggings_8|leggings_9|leggings_10|leggings_11|leggings_12
      - flag global pmsBoots:!
      - flag global pmsBoots:|:boots_1|boots_2|boots_3|boots_4|boots_5|boots_6|boots_7|boots_8|boots_9|boots_10|boots_11|boots_12

getProceduralMob:
  type: procedure
  definitions: difficulty|isBoss
  script:
  - define hp <proc[randomMobHP].context[<def[difficulty]>|<def[isBoss]>]>
  - define speed <proc[lerp].context[pmsMobSpeed|<def[difficulty]>|<def[isBoss]>]>
  - define attackDamage <proc[lerp].context[pmsAttackDamage|<def[difficulty]>|<def[isBoss]>]>
  - define knockbackResistance <proc[lerp].context[pmsKnockbackResistance|<def[difficulty]>|<def[isBoss]>]>
  #- narrate "HP: <def[hp]> Dmg: <def[attackDamage]> Spd: <def[speed]> KnockBackRes: <def[knockbackResistance]>"
  #- define randomMobs li@witch|creeper|zombie|skeleton|endermite|silverfish|blaze
  #- determine e@<def[randomMobs].random>[<def[defaultAttributes]>]

  # Take a random player who has ever played on the server and set his face to the boss
  - if <def[isBoss]> && <util.random.decimal.is[OR_LESS].than[<proc[lerp].context[pmsPlayerHeadProbability|<def[difficulty]>|<def[isBoss]>]>]> {
    - define skull ";skull=<server.list_players.random.name>"
  }
  - if <util.random.decimal.is[OR_LESS].than[<proc[lerp].context[pmsBabyPercentage|<def[difficulty]>|<def[isBoss]>]>]> {
    - define isBaby ";age=baby"
  }
  # TODO knockbackresistence as parameter
  - define defaultAttributes max_health=<def[hp]><tern[<def[skull].exists>]:<def[skull]>||>;health=<def[hp]>;movementSpeed=<def[speed]>;attackDamage=<def[attackDamage]>;followRange=64;knockbackResistance=<def[knockbackResistance]>

  - if <def[isBoss].exists> && <def[isBoss].is[==].to[true]> {
    - define bossAttributes custom_name=<proc[myrandomBossName].context[<def[difficulty]>]>;%defaultAttributes%
    - random {
      # TODO ;villager=true
      #- determine e@ghast[custom_name=<proc[myrandomBossName]>;<def[defaultAttributes]>]
      - determine e@skeleton[%bossAttributes%;skeleton=WITHER]
      - determine e@pig_zombie[%bossAttributes%]
      - determine e@zombie[%bossAttributes%]
    }
  }
  else {
    - define defaultAttributes "custom_name=<gray>Lv <def[difficulty].mul[<fl@pmsMobToBossDifficulty>].round>;%defaultAttributes%"
    - random {
      - determine e@witch[<def[defaultAttributes]>]
      - determine e@creeper[<def[defaultAttributes]>]
      - determine e@creeper[powered=true;<def[defaultAttributes]>]
      # TODO ;jockey=true
      #- determine e@endermite[<def[defaultAttributes]>]
      #- determine e@silverfish[<def[defaultAttributes]>]
      - determine e@blaze[<def[defaultAttributes]>]
      - determine e@zombie[<def[defaultAttributes]><tern[<def[isBaby].exists>]:<def[isBaby]>||>]
      - determine e@pig_zombie[<def[defaultAttributes]><tern[<def[isBaby].exists>]:<def[isBaby]>||>]
      - determine e@skeleton[<def[defaultAttributes]>]
      #- determine e@rabbit[color=KILLER;<def[defaultAttributes]>]
    }
  }

randomMobHP:
    type: procedure
    definitions: difficulty|isBoss
    script:
    - define mobHP <proc[lerp].context[pmsMobHP|<def[difficulty]>|<def[isBoss]>]>
    - determine <proc[gaussRand].context[<def[mobHP]>|1|<fl@pmsMobHP.get[2]>].round>

gaussRand:
  type: procedure
  # TODO implement sigma as percentage
  definitions: myinput|min|max
  script:
  - define returnValue <math:<util.random.gauss>*(%myinput%/16)+%myinput%>
  - if <def[min].exists> && <def[max].exists> {
    - if <el@val[%returnValue%].is[LESS].than[<el@val[%min%]>]> {
      - define returnValue %min%
    }
    else if <el@val[%returnValue%].is[MORE].than[<el@val[%max%]>]> {
      - define returnValue %max%
    }
  }
  - determine %returnValue%

randomitem:
    type: procedure
    definitions: globalflagname|difficulty|isBoss
    script:
    - define itemlist <fl@%globalflagname%.as_list>
    - if !<def[isBoss].exists> || <def[isBoss].is[==].to[false]> {
      # Normal mob's item level will be 1/2 of the boss item level
      - define difficulty <def[difficulty].mul[<fl@pmsMobToBossDifficulty>].round>
    }

    - define itemlevel <proc[lerpIndex].context[%globalflagname%|%difficulty%]>
    # weigh generated item levels closer to max level. E.g: difficulty 50/100 -> most itemlevels will be in range 30-50
    # E.g. Boss with level 50 will get item 5 (if 10 items in list).
    - define myrand <util.random.int[<util.random.int[0].to[<def[itemlevel]>]>].to[<def[itemlevel]>]>
    - determine <def[itemlist].get[%myrand%]>

# Linear interpolation
lerp:
  type: procedure
  # passing the list directly always only passed the first item from the list, thus globalflagname
  definitions: globalflagname|difficulty|isBoss
  script:
    - if !<def[difficulty].exists> {
      - announce to_console "PMS: Difficulty not specified, assuming 50%."
      - define difficulty <fl@pmsMaxDifficulty.div[2]>
    }

    - if !<def[isBoss].exists> || <def[isBoss].is[==].to[false]> {
      - define difficulty <def[difficulty].mul[<fl@pmsMobToBossDifficulty>].round>
    }

    - define valuelist <fl@%globalflagname%.as_list>

    - if <def[valuelist].exists> && <el@val[<def[valuelist].size>].is[MORE].than[1]> {

      # 0.6 - 0.2 = 0.4
      - define rangeDelta <math:<def[valuelist].get[2]>-<def[valuelist].get[1]>>
      # 60/100 * 0.4 = 0,24 -> 0,24+0,2 = 0,44 -> calculated 60% from 0.2...0.6
      - define returnlevel <math:(%difficulty%/<fl@pmsMaxDifficulty>)*%rangeDelta%+<def[valuelist].get[1]>>
    }
    else {
      # Couldn't find range from provided list, trying to return first item in list. Will be null if list is empty.
      - define returnLevel <def[valuelist].get[1]>
    }
    - determine <def[returnlevel]>

lerpIndex:
  type: procedure
  definitions: globalflagname|difficulty
  script:
    - if !<def[difficulty].exists> {
      - narrate "Difficulty not specified, assuming 50%"
      - define difficulty <fl@pmsMaxDifficulty.div[2]>
    }
    # map difficulty to number of items in list. Must be integer to access list via .get[i] later, thus .round at the end
    - define itemlevel <def[difficulty].div[<fl@pmsMaxDifficulty>].mul[<fl@%globalflagname%.as_list.size>].round>
    - determine <def[itemlevel]>

# each player adds pmsDifficultyIncreasePerPlayer (percent) difficulty
playerCountDifficulty:
  type: procedure
  definitions: difficulty
  script:
  - define playerCount <player.location.find.players.within[36].size>
  # (( 15 * 3 - 15 )/100) * <fl@pmsMaxDifficulty>
  - if <def[playerCount].is[MORE].than[1]> {
    - define temp <math:((<fl@pmsDifficultyIncreasePerPlayer>*%playerCount%-<fl@pmsDifficultyIncreasePerPlayer>)/100+1)*<def[difficulty]>>
    - determine <def[temp].round>
  }
  else {
    - determine <def[difficulty]>
  }


########################################################################################################################################
# spawnSummonWrapper
########################################################################################################################################
spawnSummonWrapper:
  type: task
  definitions: as_executor|location|entity|equip|difficulty|isBoss
  script:
  - define entityAttributes <def[entity].split[regex:\w@\w+\[]>
  - define entityAttributes <def[entityAttributes].substring[0,<def[entityAttributes].length.sub_int[1]>].split[;]>

  - foreach <def[entityAttributes]> {
    - if <def[value].contains[<el@val[=]>]> {
      - if <def[value].contains[custom_name]> {
        - define custom_name <def[value].split[<el@val[=]>].get[2]>
      }
      else if <def[value].contains[max_health]> {
        - define max_health <def[value].split[<el@val[=]>].get[2]>
      }
      else if <def[value].contains[health]> {
        - define health <def[value].split[<el@val[=]>].get[2]>
      }
      else if <def[value].contains[movementSpeed]> {
        - define movementSpeed <def[value].split[<el@val[=]>].get[2]>
      }
      else if <def[value].contains[attackDamage]> {
        - define attackDamage <def[value].split[<el@val[=]>].get[2]>
      }
      else if <def[value].contains[followRange]> {
        - define followRange <def[value].split[<el@val[=]>].get[2]>
      }
      else if <def[value].contains[knockbackResistance]> {
        - define knockbackResistance <def[value].split[<el@val[=]>].get[2]>
      }
      else if <def[value].contains[skeleton]> && <def[value].split[<el@val[=]>].get[2].is[==].to[WITHER]> {
        - define mobType "SkeletonType:1"
      }
      else if <def[value].contains[powered]> && <def[value].split[<el@val[=]>].get[2].is[==].to[true]> {
        # TODO: radius and fuse should be variables
        - define poweredCreeper "ExplosionRadius:3,Fuse:30,powered:1"
      }
      else if <def[value].contains[villager]> && <def[value].split[<el@val[=]>].get[2].is[==].to[true]> {
        - define isVillager "IsVillager:1"
      }
      else if <def[value].contains[age]> && <def[value].split[<el@val[=]>].get[2].is[==].to[baby]> {
        - define age "IsBaby:1"
      }
      else if <def[value].contains[skull]> {
        # TODO if player skull is taken, name "Xericore the Shadow" or something
        - define skull "id:skull,Damage:3,tag:{SkullOwner:<def[value].split[<el@val[=]>].get[2]>}"
      }
      else if <def[value].contains[jockey]> && <def[value].split[<el@val[=]>].get[2].is[==].to[true]> {
        - define jockey "Riding:{id:Chicken,IsChickenJockey:1}"
      }
      #else if <def[value].contains[ActiveEffects]> {
      #  - define ActiveEffects <def[value].split[<el@val[=]>].get[2]>
      #}
    }
  }

  # need this to correctly support conversion of pig_zombie to PigZombie
  - define summonEntity <def[entity].entity_type.to_titlecase>

  # Only (Pig)Zombies and Skeletons will have equipment
  - if <def[entity].entity_type.is[==].to[SKELETON]> || <def[entity].entity_type.is[==].to[ZOMBIE]> || <def[entity].entity_type.is[==].to[PIG_ZOMBIE]> {

    - if <def[entity].entity_type.is[==].to[PIG_ZOMBIE]> {
      - define anger "Anger:32767"
      - define summonEntity PigZombie
    }
    - define equipChance <proc[lerp].context[pmsEquipRange|<def[difficulty]>|<def[isBoss]>]>

    - define equipAttributs <def[equip].split[/]>
    - foreach <def[equipAttributs]> {
      - if <util.random.decimal.is[OR_LESS].than[<def[equipChance]>]> || <def[entity].entity_type.is[==].to[SKELETON]> {
          # Skeletons always get weapons, otherwise they don't do anything.
          - define equip true
        }
        else {
          - define equip false
        }

      - if <def[value].contains[hand]> {
        # bosses always have weapons
          - if <def[isBoss]> || <def[equip]> {
            - define hand <proc[getItemWithDurability].context[<def[value]>|<def[difficulty]>|<def[isBoss]>]>
          }
        }
        else if <def[value].contains[head]> {
          # Equip helmet always to prevent mobs from burning at day (you could use fire resistance as well, but I like this better)
          - define head <proc[getItemWithDurability].context[<def[value]>|<def[difficulty]>|<def[isBoss]>]>
        }
        else if <def[value].contains[chest]> && <def[equip]> {
          - define chest <proc[getItemWithDurability].context[<def[value]>|<def[difficulty]>|<def[isBoss]>]>
        }
        else if <def[value].contains[legs]> && <def[equip]> {
          - define leggings <proc[getItemWithDurability].context[<def[value]>|<def[difficulty]>|<def[isBoss]>]>
        }
        else if <def[value].contains[boots]> && <def[equip]> {
          - define boots <proc[getItemWithDurability].context[<def[value]>|<def[difficulty]>|<def[isBoss]>]>
        }
        else if <def[value].contains[DropChances]> {
          - define DropChances <def[value]>
        }
      }
    }

  - execute <def[as_executor]> "summon <def[summonEntity]> <def[location].x> <def[location].y> <def[location].z>
    {Equipment:[
    {<tern[<def[hand].exists>]:<def[hand]>||>},
    {<tern[<def[boots].exists>]:<def[boots]>||>},
    {<tern[<def[leggings].exists>]:<def[leggings]>||>},
    {<tern[<def[chest].exists>]:<def[chest]>||>},
    {<tern[<def[skull].exists>]:<def[skull]>||<tern[<def[head].exists>]:<def[head]>||>>}]<tern[<def[custom_name].exists>]:,CustomName:<def[custom_name]>||>, Attributes : [ <tern[<def[max_health].exists>]:{Name : generic.maxHealth,Base : <def[max_health]>}||>
    <tern[<def[movementSpeed].exists>]:,
    {Name : generic.movementSpeed,Base : <def[movementSpeed]>}||> <tern[<def[attackDamage].exists>]:,
    {Name : generic.attackDamage,Base : <def[attackDamage]>}||> <tern[<def[followRange].exists>]:,
    {Name : generic.followRange,Base : <def[followRange]>}||> <tern[<def[knockbackResistance].exists>]:,
    {Name : generic.knockbackResistance,Base : <def[knockbackResistance]>}||>]
    <tern[<def[DropChances].exists>]:,<def[DropChances]>||><tern[<def[mobType].exists>]:,<def[mobType]>||>
    <tern[<def[anger].exists>]:,<def[anger]>||>
    <tern[<def[poweredCreeper].exists>]:,<def[poweredCreeper]>||>
    #,ActiveEffects:[{Id:12,Amplifier:1,Duration:999999}]
    <tern[<def[age].exists>]:,<def[age]>||>
    <tern[<def[isVillager].exists>]:,<def[isVillager]>||>
    <tern[<def[jockey].exists>]:,<def[jockey]>||>}"
  #<tern[<def[ActiveEffects].exists>]:,<proc[getActiveEffectsFormatted].context[<def[ActiveEffects]>]>||>

getItemWithDurability:
  type: procedure
  definitions: item|difficulty|isBoss
  script:
  - define itemName <def[item].split[:].get[2]>
  - define maxDurability <i@%itemName%.max_durability>
  - define durabilityDifficulty <proc[lerp].context[pmsItemDamaged|<def[difficulty]>|<def[isBoss]>]>

  - define randDurability <proc[gaussRand].context[<math:%durabilityDifficulty%*%maxDurability%>|0|%maxDurability%].round>
  - determine <i@%itemName%[durability=%randDurability%].json>


getActiveEffectsFormatted:
  type: procedure
  definitions: ActiveEffects
  script:
  - define tempActiveEffects ,ActiveEffects:[
  - foreach <def[ActiveEffects]> {
    - define <def[tempActiveEffects]> %tempActiveEffects%
  }
  - determine 2
  #{Id:22,Amplifier:1,Duration:999999},{Id:7,Amplifier:1,Duration:999999},{Id:16,Amplifier:1,Duration:999999}]