[GAME MODE] Kraken

Incomplete code that isn't ready for use.
18 posts Page 1 of 2
thepolm3
Scripter
Scripter
Posts: 424
Joined: Sat Feb 16, 2013 10:49 pm


This is a gamemode by hompy that I have fixed for 0.75
code:
Code: Select all

"""
by hompy

fixed for 0.75 by thepolm3
"""

from collections import deque
from math import cos, sin, sqrt, ceil, pi
from random import randrange, uniform, choice
from operator import itemgetter, attrgetter
from itertools import product
 
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
from pyspades.server import Territory
from pyspades.server import orientation_data, move_object, grenade_packet
from pyspades.server import block_action, set_color, position_data
from pyspades.world import Grenade
from pyspades.common import Vertex3, Quaternion, make_color, coordinates
from pyspades.collision import vector_collision, distance_3d_vector
from pyspades.constants import *
from commands import name, add, get_player, admin
 
ALLOW_KRAKEN_COMMAND = True
 
USE_DAYCYCLE = False
RESPAWN_TIME = 15
FALLING_BLOCK_COLOR = 0x606060
FALLING_BLOCK_DAMAGE = 100
FALLING_BLOCK_Z = 0
REGEN_ONSET = 2.0
REGEN_FREQUENCY = 0.15
REGEN_AMOUNT = 3
WATER_DAMAGE = 25
GRAB_DAMAGE = 40
EYE_PAIN_TIME = 8.0
KRAKEN_BLACK = 0x000000
KRAKEN_BLOOD = make_color(120, 255, 120)
KRAKEN_EYE_SMALL = [
    ( 0, 0, -1, 0xC00000),
    ( 0, 0, -2, 0x400000),
    ( 0, 0, -3, 0xC00000),
    (-1, 0, -1, 0xFF0000),
    (-1, 0, -2, 0xC00000),
    (-1, 0, -3, 0x800000),
    ( 1, 0, -1, 0xFF0000),
    ( 1, 0, -2, 0xC00000),
    ( 1, 0, -3, 0xFFFFFF)]
KRAKEN_EYE_SMALL_CLOSED = [
    (-1, 0, -1, 0x000000),
    (-1, 0, -2, 0x000000),
    (-1, 0, -3, 0x000000),
    ( 1, 0, -1, 0x000000),
    ( 1, 0, -2, 0x000000),
    ( 1, 0, -3, 0x000000),
    ( 0, 0, -1, 0x000000),
    ( 0, 0, -2, 0x000000),
    ( 0, 0, -3, 0x000000)]
 
def conv_color(val):
    return ((val >> 16) & 255, (val >> 8) & 255, val & 255)
 
def cube(s):
    s0, s1 = -s / 2 + 1, s / 2 + 1
    return product(xrange(s0, s1), repeat = 3)
 
def prism(x, y, z, w, d, h):
    return product(xrange(x, x + w), xrange(y, y + d), xrange(z, z + h))
 
def plane(r):
    r0, r1 = -r / 2 + 1, r / 2 + 1
    return product(xrange(r0, r1), repeat = 2)
 
def disc(rr, x = 0, y = 0, min_rr = None):
    for u, v in plane(rr):
        d = u * u + v * v
        if d > rr or (min_rr and d < min_rr):
            continue
        yield x + u, y + v
 
def sphere(r, x = 0, y = 0, z = 0, min_r = None):
    rr = r * r
    min_rr = min_r and min_r * min_r
    for w, v, u in cube(r):
        d = u * u + v * v + w * w
        if d > rr or (min_r and d < min_rr):
            continue
        yield x + u, y + v, z + w
 
def aabb(x, y, z, i, j, k, w, d, h):
    return not (x < i or x > i + w or y < j or y > j + d or z < k or z > k + h)
 
def aabb_centered(x, y, z, i, j, k, s):
    return not (x < i - s or x > i + s or y < j - s or y > j + s or
        z < k - s or z > k + s)
 
def randrangerect(x1, y1, x2, y2):
    return randrange(x1, x2), randrange(y1, y2)
 
def fall_eta(height):
    return 2.0 * (height / 64.0) ** 0.75
 
def is_valid_enemy(player):
    return not (player.world_object is None or player.world_object.dead or
        player.grabbed_by or player.trapped or player.regenerating or player.god)
 
class Animated:
    blocks_per_cycle = 3
    build_interval = 0.01
    build_queue = None
    build_loop = None
    blocks = None
    
    def __init__(self, protocol):
        self.protocol = protocol
        self.build_queue = deque()
        self.build_loop = LoopingCall(self.build_cycle)
        self.build_loop.start(self.build_interval)
        self.blocks = set()
    
    def build_cycle(self):
        if not self.build_queue:
            return        
        blocks_left = self.blocks_per_cycle
        last_color = None
        while self.build_queue and blocks_left > 0:
            x, y, z, color = self.build_queue.popleft()
            if color != last_color:
                self.protocol.set_block_color(color)
                last_color = color
            if self.protocol.build_block(x, y, z, color):
                blocks_left -= 1
 
class Tentacle(Animated):
    dead = False
    dying = False
    on_death = None
    on_removed = None
    parent = None
    protocol = None
    origin = None
    up = None
    orientation = None
    start_orientation = None
    target_orientation = None
    lerp_t = None
    facing = None
    sections = None
    radius = 2
    spread = radius / 2.0
    follow = None
    follow_interval = 1.3
    follow_timer = follow_interval
    initial_growth_interval = 0.2
    growth_interval = initial_growth_interval
    growth_timer = growth_interval
    blocks_destroyed = None
    last_block_destroyed = None
    growing = True
    withdraw = False
    grabbed_player = None
    max_hp = None
    
    def __init__(self, protocol, parent, (x, y, z)):
        Animated.__init__(self, protocol)
        self.parent = parent
        self.origin = Vertex3(x, y, z)
        self.up = Vertex3(0.0, 0.0, -1.0)
        self.orientation = Quaternion()
        self.facing = self.orientation.transform_vector(self.up)
        self.sections = []
        self.blocks_destroyed = []
        self.parent.tentacles.append(self)
        self.find_target()
    
    def find_target(self):
        best = None
        best_dist = None
        best_followed = None
        for player in self.protocol.players.values():
            if not is_valid_enemy(player):
                continue
            dist = distance_3d_vector(player.world_object.position, self.origin)
            followed = self.parent.is_enemy_targeted(player)
            if not best or dist < best_dist or best_followed and not followed:
                best, best_dist, best_followed = player, dist, followed
        self.follow = best
    
    def think(self, dt):
        tip = self.sections and self.sections[-1][0] or self.origin
        
        self.follow_timer -= dt
        if self.follow and not is_valid_enemy(self.follow):
            self.find_target()
            if not self.follow:
                self.growth_timer = 0.66
                self.growing = False
                self.withdraw = True
        elif self.follow and self.follow_timer <= 0.0:
            self.follow_timer = self.follow_interval
            follow_pos = self.follow.world_object.position
            direction = follow_pos - tip
            q = self.facing.get_rotation_to(direction)
            self.start_orientation = Quaternion(*self.orientation.get())
            self.target_orientation = q * self.orientation
            self.lerp_t = 0.0
        if self.target_orientation and self.lerp_t <= 1.0:
            self.orientation = self.start_orientation.slerp(
                self.target_orientation, self.lerp_t)
            self.lerp_t += 0.02
        self.facing = self.orientation.transform_vector(self.up)
        self.facing.normalize()
        
        self.growth_timer -= dt
        if self.growth_timer <= 0.0:
            self.growth_timer = self.growth_interval
            if self.growing and self.follow:
                tip = self.grow(tip.copy())
            elif self.withdraw:
                if self.sections:
                    pos, blocks = self.sections.pop()
                    tip = pos
                    for uvw in blocks:
                        if not self.parent.is_location_inside(uvw, skip = self):
                            self.protocol.remove_block(*uvw)
                        self.blocks.discard(uvw)
                else:
                    for uvw in self.blocks:
                        if not self.parent.is_location_inside(uvw, skip = self):
                            self.protocol.remove_block(*uvw)
                    self.dead = True
                    if self.on_removed:
                        self.on_removed(self)
        
        player = self.grabbed_player
        if player:
            if self.dead or not player.world_object:
                player.grabbed_by = None
                self.grabbed_player = None
            else:
                player.set_location((tip.x, tip.y, tip.z - 1.0))
                if tip.z >= 63:
                    player.got_water_damage = True
                    player.kill(type = FALL_KILL)
                    player.got_water_damage = False
    
    def on_block_destroy(self, x, y, z, mode):
        if mode == SPADE_DESTROY and (x, y, z) in self.blocks:
            return False
    
    def on_block_removed(self, x, y, z):
        xyz = (x, y, z)
        if xyz not in self.blocks:
            return
        self.blocks.discard(xyz)
        total_damage = 0.0
        for u, v, w in self.blocks_destroyed:
            xu, yv, zw = x - u, y - v, z - w
            d = sqrt(xu*xu + yv*yv + zw*zw)
            total_damage += d >= 1.0 and 1.0 / d or 1.0
            if total_damage > self.max_hp:
                self.fracture(x, y, z)
                self.last_block_destroyed = None
                self.die()
                if self.on_death:
                    self.on_death(self)
                return
        if self.last_block_destroyed:
            self.protocol.set_block_color(KRAKEN_BLOOD)
            u, v, w = self.last_block_destroyed
            self.protocol.build_block(u, v, w, KRAKEN_BLOOD)
            self.blocks.add(self.last_block_destroyed)
        self.last_block_destroyed = xyz
        self.blocks_destroyed.append(xyz)
    
    def die(self):
        self.follow = None
        self.target_orientation = None
        if self.grabbed_player:
            self.grabbed_player.grabbed_by = None
        self.grabbed_player = None
        self.growth_timer = 0.66
        speedup = 2.0 + max(len(self.sections) / 140.0, 1.0)
        self.growth_interval = self.initial_growth_interval / speedup
        self.growing = False
        self.withdraw = True
        self.dying = True
    
    def fracture(self, x, y, z):
        protocol = self.protocol
        radius = self.radius
        for uvw in sphere(int(radius * 1.5), x, y, z):
            if not self.parent.is_location_inside(uvw, skip = self):
                protocol.remove_block(*uvw)
            self.blocks.discard(uvw)
        to_remove = []
        breakpoint = False
        while self.sections:
            pos, blocks = self.sections.pop()
            for uvw in blocks:
                if not self.parent.is_location_inside(uvw, skip = self):
                    if breakpoint:
                        protocol.remove_block(*uvw)
                    else:
                        to_remove.append(uvw)
                self.blocks.discard(uvw)
            if breakpoint:
                break
            i, j, k = pos.get()
            breakpoint = aabb_centered(x, y, z, i, j, k, radius)
        if self.sections:
            self.sections.pop()
        for u, v, w in to_remove:
            protocol.remove_block(u, v, w)
    
    def grow(self, tip):
        if self.sections:
            tip += self.facing * self.spread
        map = self.protocol.map
        radius = self.radius
        ix, iy, iz = int(tip.x), int(tip.y), int(tip.z)
        blocks = []
        destroyed = 0
        for x, y, z in sphere(radius, ix, iy, iz):
            if (x < 0 or x >= 512 or y < 0 or y >= 512 or 
                z < 0 or z >= 63):
                continue
            xyz = (x, y, z)
            if xyz not in self.blocks:
                if not map.get_solid(x, y, z):
                    blocks.append(xyz)
                    self.blocks.add(xyz)
                    self.build_queue.append(xyz + (KRAKEN_BLACK,))
                elif not self.parent.is_location_inside(xyz, skip = self):
                    destroyed += 1
        if destroyed >= radius:
            for x, y, z in sphere(radius + 2, ix, iy, iz, min_r = radius):
                if self.parent.is_location_inside((x, y, z)):
                    continue
                self.protocol.remove_block(x, y, z)
            self.protocol.create_explosion_effect(tip)
        for player in self.protocol.players.values():
            if not is_valid_enemy(player):
                continue
            pos = player.world_object.position
            if vector_collision(pos, tip, radius * 0.75):
                self.follow = None
                self.target_orientation = None
                self.growth_timer = 0.4
                self.growing = False
                self.withdraw = True
                self.grabbed_player = player
                player.grabbed_by = self
                player.set_location((tip.x, tip.y, tip.z - 1.0))
                player.hit(GRAB_DAMAGE)
                break
        self.sections.append((tip, blocks))
        return tip
 
class Eye():
    parent = None
    protocol = None
    dead = False
    blocks = None
    origin_x = None
    pos = None
    base = None
    hits = None
    look_interval_min = 0.8
    look_interval_max = 2.5
    look_timer = look_interval_max
    on_hit = None
    create_call = None
    
    def __init__(self, parent, base, ox, oy, oz, hits = 3):
        self.parent = parent
        self.protocol = parent.protocol
        self.blocks = set()
        self.pos = parent.origin.copy().translate(ox, oy, oz)
        self.origin_x = self.pos.x
        self.base = base[:]
        self.hits = hits
        parent.eyes.append(self)
    
    def think(self, dt):
        if not self.blocks:
            return
        self.look_timer -= dt
        if self.look_timer <= 0.0:
            self.look_timer = uniform(self.look_interval_min,
                self.look_interval_max)
            old_x = self.pos.x
            self.pos.x = max(self.origin_x - 1, min(self.origin_x + 1,
                self.pos.x + choice([-1, 1])))
            if old_x != self.pos.x:
                old_blocks = self.blocks
                self.blocks = set()
                self.create_instant()
                old_blocks -= self.blocks
                self.protocol.set_block_color(KRAKEN_BLACK)
                for x, y, z in old_blocks:
                    self.protocol.build_block(x, y, z, KRAKEN_BLACK, 
                        force = True)
    
    def create(self, block_queue = None, close = False):
        if block_queue is None:
            block_queue = deque(self.base)
        last_color = None
        x, y, z = self.pos.get()
        x_d = None
        while block_queue:
            u, v, w, color = block_queue[0]
            if x_d is None:
                x_d = abs(u)
            elif abs(u) != x_d:
                break
            if color != last_color:
                self.protocol.set_block_color(color)
                last_color = color
            u, v, w = x + u, y + v, z + w
            uvw = (u, v, w)
            self.protocol.build_block(u, v, w, color, force = True)
            if not close:
                self.parent.head.discard(uvw)
                self.blocks.add(uvw)
            block_queue.popleft()
        if block_queue:
            self.create_call = reactor.callLater(0.25, self.create, block_queue)
    
    def create_instant(self, block_list = None):
        if block_list is None:
            block_list = self.base
        last_color = None
        x, y, z = self.pos.get()
        block_list = sorted(block_list, key = itemgetter(3))
        for u, v, w, color in block_list:
            if color != last_color:
                self.protocol.set_block_color(color)
                last_color = color
            u, v, w = x + u, y + v, z + w
            uvw = (u, v, w)
            self.protocol.build_block(u, v, w, color, force = True)
            self.parent.head.discard(uvw)
            self.blocks.add(uvw)
    
    def on_block_removed(self, x, y, z):
        xyz = (x, y, z)
        if self.dead or xyz not in self.blocks:
            return
        protocol = self.protocol
        protocol.create_explosion_effect(Vertex3(x, y, z))
        self.parent.build_queue.append((x, y, z, KRAKEN_BLOOD))
        self.hits -= 1
        if self.hits > 0:
            self.pain()
            uvw = (x - self.pos.x, y - self.pos.y, z - self.pos.z)
            i = [uvwc[:-1] for uvwc in self.base].index(uvw)
            self.base[i] = uvw + (KRAKEN_BLOOD,)
        else:
            self.close()
            self.dead = True
        if self.on_hit:
            self.on_hit(self)
    
    def close(self):
        self.parent.head.update(self.blocks)
        self.blocks.clear()
        if self.create_call and self.create_call.active():
            self.create_call.cancel()
        reactor.callLater(0.5, self.create, deque(KRAKEN_EYE_SMALL_CLOSED),
            close = True)
    
    def pain(self):
        self.close()
        reactor.callLater(EYE_PAIN_TIME, self.create)
        self.look_timer = EYE_PAIN_TIME + self.look_interval_min
 
class Kraken(Animated):
    dead = False
    origin = None
    tentacles = None
    head = None
    eyes = None
    max_hp = 10.0
    hp = max_hp
    size = 7
    on_last_tentacle_death = None
    on_death = None
    on_removed = None
    finally_call = None
    phase = 0
    
    def __init__(self, protocol, (x, y, z)):
        Animated.__init__(self, protocol)
        self.origin = Vertex3(x, y, z)
        self.head = set()
        self.eyes = []
        self.tentacles = []
    
    def is_location_inside(self, location, skip = None):
        if location in self.head:
            return True
        for eye in self.eyes:
            if location in eye.blocks:
                return True
        for t in self.tentacles:
            if t is not skip and location in t.blocks:
                return True
        return False
    
    def is_enemy_targeted(self, player):
        for t in self.tentacles:
            if t.follow is player:
                return True
        return False
    
    def on_block_destroy(self, x, y, z, mode):
        for t in self.tentacles:
            if t.on_block_destroy(x, y, z, mode) == False:
                return False
    
    def on_block_removed(self, x, y, z):
        eye_died = False
        for eye in self.eyes:
            eye.on_block_removed(x, y, z)
            eye_died = eye_died or eye.dead
        if eye_died:
            self.eyes = [eye for eye in self.eyes if not eye.dead]
            if not self.eyes:
                self.die()
        
        for t in self.tentacles:
            t.on_block_removed(x, y, z)
    
    def die(self):
        protocol = self.protocol
        def remove(this, remover, blocks):
            if blocks:
                remover(*blocks.pop())
                reactor.callLater(0.01, this, this, remover, blocks)
            elif self.on_removed:
                self.on_removed(self)
        def explode(this, effect, blocks, left):
            x = self.origin.x + uniform(-5.0, 5.0)
            y = self.origin.y + self.size + 1.0
            z = self.origin.z + uniform(-15.0, 0.0)
            effect(Vertex3(x, y, z))
            if not blocks or left <= 0:
                return
            delay = uniform(0.3, 0.8)
            left -= 1
            reactor.callLater(delay, this, this, effect, blocks, left)
        remove(remove, protocol.remove_block, self.head)
        explode(explode, protocol.create_explosion_effect, self.head, 10)
        
        self.dead = True
        for t in self.tentacles:
            t.die()        
        if self.on_death:
            self.on_death(self)
    
    def think(self, dt):
        for eye in self.eyes:
            eye.think(dt)
        
        rebuild_list = False
        for t in self.tentacles:
            t.think(dt)
            rebuild_list = rebuild_list or t.dead
        if rebuild_list:
            self.tentacles = [t for t in self.tentacles if not t.dead]
            if not self.tentacles and self.on_last_tentacle_death:
                self.on_last_tentacle_death(self)
    
    def hit(self, value, rate):
        hp_bar = self.protocol.hp_bar
        if not hp_bar.shown:
            hp_bar.progress = 1.0 - self.hp / self.max_hp
            hp_bar.show()
        self.hp = max(self.hp - value, 0)
        previous_rate = hp_bar.rate
        hp_bar.get_progress(True)
        hp_bar.rate = rate
        hp_bar.update_rate()
        hp_bar.send_progress()
        target_progress = 1.0 - self.hp / self.max_hp
        delay = (target_progress - hp_bar.progress) / hp_bar.rate_value
        hp_call = hp_bar.hp_call
        if hp_call and hp_call.active():
            if previous_rate == 0:
                hp_call.cancel()
            else:
                hp_call.reset(delay)
                return
        hp_bar.hp_call = reactor.callLater(delay, hp_bar.stop)
    
    def create_head(self, head_list, height = None):
        height = height or len(head_list)
        x, y, z = self.origin.get()
        for d in head_list[-height:]:
            for u, v in d:
                xyzc = (x + u, y + v, z, KRAKEN_BLACK)
                self.build_queue.append(xyzc)
                self.head.add(xyzc[:-1])
            z -= 1
        if height < len(head_list):
            delay = 0.6
            reactor.callLater(delay, self.create_head, head_list, height + 6)
 
force_boss = False
 
@admin
def kraken(connection, value = None):
    global force_boss
    protocol = connection.protocol
    if protocol.game_mode != TC_MODE:
        return 'Unfortunately, the game mode is required to be TC. Change it then restart'
    if not protocol.boss_ready:
        force_boss = True
        return 'The next map will be kraken-ready. Change maps then try again'
    if protocol.boss:
        return "There is already a kraken! Why can't I hold all these krakens?"
    try:
        x, y = coordinates(value)
    except (ValueError):
        return 'Need coordinates where to spawn the kraken, e.g /kraken E3'
    start_kraken(protocol, max(x, 64), max(y, 64))
 
if ALLOW_KRAKEN_COMMAND:
    add(kraken)
 
def start_kraken(protocol, x, y, hardcore = False, finally_call = None):
    y += 32
    boss = Kraken(protocol, (x, y - 12, 63))
    protocol.boss = boss
    if USE_DAYCYCLE and protocol.daycycle_loop.running:
        protocol.daycycle_loop.stop()
    
    arena = getattr(protocol.map_info.info, 'arena', None)
    if arena:
        arena_center = (int((arena[2] - arena[0]) / 2.0 + arena[0]),
            int((arena[3] - arena[1]) / 2.0 + arena[1]))
        arena_radius = min(arena[2] - arena[0], arena[3] - arena[1]) / 2.0
    
    def randring():
        min_r, max_r = 12.0, 32.0
        r = uniform(min_r, max_r)
        a = uniform(0.0, pi)
        return x + cos(a) * r, y + sin(a) * r, 63
    
    def randring_arena():
        if not arena:
            return randring()
        r = uniform(arena_radius, arena_radius * 1.2)
        a = uniform(0.0, 2*pi)
        x, y = arena_center
        return x + cos(a) * r, y + sin(a) * r, 63
    
    def minor_hit(caller = None):
        boss.hit(1.0, 1)
        caller.on_removed = None
    
    def major_hit(caller = None):
        boss.hit(3.0, 1)
    
    def major_hit_and_progress(caller = None):
        caller.on_hit = major_hit
        major_hit()
        progress()
    
    def major_hit_and_pain(caller = None):
        major_hit()
        boss_alive = False
        for eye in caller.parent.eyes:
            if eye is not caller and not eye.dead:
                eye.pain()
                boss_alive = True
        if boss_alive and caller.dead:
            falling_blocks_start()
    
    def respawn_tentacle(caller = None):
        if boss and not boss.dead:
            reactor.callLater(5.0, spawn_tentacles, 1, True)
    
    def spawn_tentacles(amount, respawn = False, fast = False, arena = False,
        no_hit = False):
        if not hardcore:
            toughness = max(3.0, min(10.0, len(protocol.players) * 0.5))
        else:
            toughness = max(5.0, min(13.0, len(protocol.players) * 0.85))
        if boss and not boss.dead:
            for i in xrange(amount):
                origin = randring_arena() if arena else randring()
                t = Tentacle(protocol, boss, origin)
                t.max_hp = toughness
                t.growth_timer = uniform(i * 1.0, i * 1.2)
                if hardcore:
                    t.initial_growth_interval *= 0.8
                if fast:
                    t.initial_growth_interval *= 0.5
                else:
                    t.follow_timer = 2.0
                t.growth_interval = t.initial_growth_interval
                if respawn:
                    t.on_removed = respawn_tentacle
                elif not no_hit:
                    t.on_death = minor_hit
                    t.on_removed = minor_hit
    
    def falling_blocks_cycle():
        alive_players = filter(is_valid_enemy, protocol.players.values())
        if not alive_players:
            return
        player = choice(alive_players)
        x, y, z = player.world_object.position.get()
        protocol.create_falling_block(int(x), int(y), randrange(2, 4), 2)
    
    def falling_blocks_start():
        for i in range(20):
            reactor.callLater(i * 0.4, falling_blocks_cycle)
    
    def squid_head():
        h = []
        for i in xrange(37, 5, -2):
            h.append(list(disc(i, min_rr = i - 15)))
        return h
    
    def squid_head_large():
        h = []
        for i in xrange(42, 3, -2):
            ii = int(i ** 1.3)
            h.append(list(disc(ii, y = int(sqrt(i)), min_rr = i + 10)))
        return h
    
    def regenerate_players():
        for player in protocol.players.values():
            player.trapped = False
            player.last_hit = reactor.seconds()
            player.regenerating = True
            if not player.world_object.dead:
                player.regen_loop.start(REGEN_FREQUENCY)
            else:
                player.spawn(player.world_object.position.get())
    
    def round_end(caller = None):
        regenerate_players()
        reactor.callLater(8.0, progress)
    
    def round_end_delay(caller = None):
        reactor.callLater(10.0, round_end)
    
    def round_start(caller = None):
        for player in protocol.players.values():
            player.regenerating = False
    
    def progress_delay(caller = None):
        reactor.callLater(6.0, progress)
    
    def victory(caller = None):
        regenerate_players()
        if USE_DAYCYCLE:
            protocol.current_time = 23.30
            protocol.update_day_color()
    
    def cleanup(caller = None):
        round_start()
        protocol.boss = None
        if USE_DAYCYCLE and protocol.daycycle_loop.running:
            protocol.daycycle_loop.stop()
        if caller.finally_call:
            caller.finally_call(caller)
    
    def red_sky():
        if USE_DAYCYCLE:
            protocol.day_colors = [
                ( 0.00, (0.5527, 0.24, 0.94), False),
                ( 0.10, (0.0,    0.05, 0.05), True),
                ( 0.20, (0.0,    1.00, 0.34), False),
                (23.30, (0.0,    1.00, 0.34), False),
                (23.50, (0.5527, 0.24, 0.94), False)]
            protocol.current_time = 0.00
            protocol.target_color_index = 0
            protocol.update_day_color()
            if not protocol.daycycle_loop.running:
                protocol.daycycle_loop.start(protocol.day_update_frequency)
    
    progress = None
    
    def progress_normal(caller = None):
        boss.phase += 1
        round_start()
        
        if boss.phase == 1:
            boss.on_last_tentacle_death = progress_delay
            spawn_tentacles(2)
        elif boss.phase == 2:
            boss.on_last_tentacle_death = round_end
            spawn_tentacles(4)
        elif boss.phase == 3:
            boss.on_last_tentacle_death = round_end
            spawn_tentacles(3, fast = True)
        elif boss.phase == 4:
            boss.on_last_tentacle_death = None
            boss.on_death = round_end_delay
            boss.size = 7
            boss.create_head(squid_head())
            eye = Eye(boss, KRAKEN_EYE_SMALL, 0, 5, -1, hits = 5)
            eye.on_hit = major_hit_and_progress
            reactor.callLater(7.0, eye.create)
        elif boss.phase == 5:
            spawn_tentacles(3, respawn = True)
            spawn_tentacles(2, arena = True, no_hit = True)
        elif boss.phase == 6:
            protocol.send_chat('LOOK UP!', global_message = None)
            falling_blocks_start()
            reactor.callLater(15.0, round_end)
        elif boss.phase == 7:
            boss.dead = False
            boss.on_last_tentacle_death = round_end
            spawn_tentacles(4, fast = True, arena = True)
        elif boss.phase == 8:
            red_sky()
            boss.on_last_tentacle_death = None
            boss.on_death = victory
            boss.on_removed = cleanup
            boss.finally_call = finally_call
            boss.origin.y -= 24
            boss.size = 16
            boss.create_head(squid_head_large())
            eye = Eye(boss, KRAKEN_EYE_SMALL, 0, 16, -2, hits = 4)
            eye.on_hit = major_hit_and_pain
            reactor.callLater(16.0, eye.create)
            eye = Eye(boss, KRAKEN_EYE_SMALL, 0, 14, -6, hits = 4)
            eye.on_hit = major_hit_and_pain
            reactor.callLater(16.0, eye.create)
            reactor.callLater(18.0, spawn_tentacles, 5, respawn = True)
    
    def progress_hardcore(caller = None):
        boss.phase += 1
        round_start()
        
        if boss.phase == 1:
            boss.on_last_tentacle_death = progress_delay
            spawn_tentacles(3)
            falling_blocks_start()
        elif boss.phase == 2:
            boss.on_last_tentacle_death = round_end
            spawn_tentacles(4, fast = True)
        elif boss.phase == 3:
            boss.on_last_tentacle_death = None
            boss.on_death = round_end_delay
            boss.size = 7
            boss.create_head(squid_head())
            eye = Eye(boss, KRAKEN_EYE_SMALL, 0, 5, -1, hits = 8)
            eye.look_interval_min *= 0.8
            eye.look_interval_max *= 0.6
            eye.on_hit = major_hit_and_progress
            reactor.callLater(7.0, eye.create)
        elif boss.phase == 4:
            spawn_tentacles(3, respawn = True)
            spawn_tentacles(3, arena = True, no_hit = True)
        elif boss.phase == 5:
            boss.dead = False
            boss.on_last_tentacle_death = round_end
            spawn_tentacles(5, fast = True, arena = True)
        elif boss.phase == 6:
            red_sky()
            boss.on_last_tentacle_death = None
            boss.on_death = victory
            boss.on_removed = cleanup
            boss.finally_call = finally_call
            boss.origin.y -= 24
            boss.size = 16
            boss.create_head(squid_head_large())
            eye = Eye(boss, KRAKEN_EYE_SMALL, 0, 16, -2, hits = 6)
            eye.look_interval_min *= 0.8
            eye.look_interval_max *= 0.6
            eye.on_hit = major_hit_and_pain
            reactor.callLater(16.0, eye.create)
            eye = Eye(boss, KRAKEN_EYE_SMALL, 0, 14, -6, hits = 6)
            eye.look_interval_min *= 0.8
            eye.look_interval_max *= 0.6
            eye.on_hit = major_hit_and_pain
            reactor.callLater(16.0, eye.create)
            reactor.callLater(18.0, spawn_tentacles, 5, respawn = True)
            reactor.callLater(14.0, falling_blocks_start)
    
    boss.blocks_per_cycle = 2
    boss.build_interval = 0.01
    if not hardcore:
        progress = progress_normal
        boss.hp = boss.max_hp = 2.0 + 4.0 + 3.0 + 5*3.0 + 4.0 + (4 + 4)*3.0
    else:
        progress = progress_hardcore
        boss.hp = boss.max_hp = 3.0 + 4.0 + 8*3.0 + 5.0 + (6 + 6)*3.0
    progress()
    return boss
 
class BossTerritory(Territory):
    shown = False
    hp_call = None
    
    def add_player(self, player):
        return
    
    def remove_player(self, player):
        return
    
    def update_rate(self):
        self.rate_value = self.rate * TC_CAPTURE_RATE
        self.capturing_team = (self.rate_value < 0 and
            self.protocol.blue_team or self.protocol.green_team)
        self.start = reactor.seconds()
    
    def show(self):
        self.shown = True
        for player in self.protocol.players.values():
            self.update_for_player(player)
    
    def hide(self):
        self.shown = False
        self.update()
    
    def stop(self):
        self.rate = 0
        self.get_progress(True)
        self.update_rate()
        self.send_progress()
        self.hp_call = reactor.callLater(3.0, self.hide)
    
    def update_for_player(self, connection, orientation = None):
        x, y, z = orientation or connection.world_object.orientation.get()
        v = Vertex3(x, y, 0.0)
        v.normalize()
        v *= -10.0
        v += connection.world_object.position
        move_object.object_type = self.id
        move_object.state = self.team and self.team.id or NEUTRAL_TEAM
        move_object.x = v.x
        move_object.y = v.y
        move_object.z = v.z
        connection.send_contained(move_object)
 
def apply_script(protocol, connection, config):
    class BossProtocol(protocol):
        game_mode = TC_MODE
        
        boss = None
        boss_ready = False
        hp_bar = None
        
        def start_kraken(self, x, y, hardcore = False, finally_call = None):
            return start_kraken(self, x, y, hardcore, finally_call)
        
        def is_indestructable(self, x, y, z):
            if self.boss:
                if self.boss.head and (x, y, z) in self.boss.head:
                    return True
            return protocol.is_indestructable(self, x, y, z)
        
        def on_world_update(self):
            if self.boss:
                self.boss.think(UPDATE_FREQUENCY)
            protocol.on_world_update(self)
        
        def on_map_change(self, map):
            self.boss = None
            self.boss_ready = False
            self.hp_bar = None
            protocol.on_map_change(self, map)
        
        def get_cp_entities(self):
            global force_boss
            if force_boss or getattr(self.map_info.info, 'boss', False):
                if USE_DAYCYCLE:
                    if self.daycycle_loop and self.daycycle_loop.running:
                        self.daycycle_loop.stop()
                force_boss = False
                self.boss_ready = True
                self.hp_bar = BossTerritory(0, self, 0.0, 0.0, 0.0)
                self.hp_bar.team = self.green_team
                return [self.hp_bar]
            return protocol.get_cp_entities(self)
        
        def create_explosion_effect(self, position):
            self.world.create_object(Grenade, 0.0, position, None, 
                Vertex3(), None)
            grenade_packet.value = 0.0
            grenade_packet.player_id = 32
            grenade_packet.position = position.get()
            grenade_packet.velocity = (0.0, 0.0, 0.0)
            self.send_contained(grenade_packet)
        
        def falling_block_collide(self, x, y, z, size):
            if not self.map.get_solid(x, y, z):
                new_z = self.map.get_z(x, y)
                if new_z > z:
                    remaining = fall_eta(new_z - z)
                    reactor.callLater(remaining, self.falling_block_collide,
                        x, y, new_z, size)
                    return
            for player in self.players.values():
                i, j, k = player.world_object.position.get()
                s = size + 3.0
                if aabb(i, j, k, x - 1.5, y - 1.5, z - 5.0, s, s, 6.0):
                    player.hit(FALLING_BLOCK_DAMAGE, type = FALL_KILL)
            half_size = int(ceil(size / 2.0))
            ox, oy = x - half_size, y - half_size
            for u, v, w in prism(ox, oy, z - 1, size, size, 3):
                self.remove_block(u, v, w, user = True)
            self.create_explosion_effect(Vertex3(x, y, z))
        
        def create_falling_block(self, x, y, size, height):
            self.set_block_color(FALLING_BLOCK_COLOR)
            half_size = int(ceil(size / 2.0))
            ox, oy = x - half_size, y - half_size
            for u, v, w in prism(ox, oy, FALLING_BLOCK_Z, size, size, height):
                self.build_block(u, v, w, FALLING_BLOCK_COLOR)
            self.remove_block(ox, oy, FALLING_BLOCK_Z)
            
            z = self.map.get_z(x, y)
            eta = fall_eta(z - FALLING_BLOCK_Z)
            reactor.callLater(eta, self.falling_block_collide, x, y, z, size)
        
        def set_block_color(self, color):
            set_color.value = color
            set_color.player_id = 32
            self.send_contained(set_color, save = True)
        
        def remove_block(self, x, y, z, user = False):
            if z >= 63:
                return False
            self.map.remove_point(x, y, z)
            block_action.value = DESTROY_BLOCK
            block_action.player_id = 32
            block_action.x = x
            block_action.y = y
            block_action.z = z
            self.send_contained(block_action)
            return True
        
        def build_block(self, x, y, z, color, force = False):
            if force:
                self.remove_block(x, y, z)
            if not self.map.get_solid(x, y, z):
                self.map.set_point(x, y, z, (0,0,0))
                set_color.value = make_color(0,0,0)
                block_action.value = BUILD_BLOCK
                block_action.player_id = 32
                block_action.x = x
                block_action.y = y
                block_action.z = z
                self.send_contained(block_action)
                self.send_contained(set_color)
                return True
            return False
    
    class BossConnection(connection):
        regenerating = False
        trapped = False
        got_water_damage = False
        grabbed_by = None
        last_hit = None
        regen_loop = None
        
        def __init__(self, *arg, **kw):
            connection.__init__(self, *arg, **kw)
            self.regen_loop = LoopingCall(self.regen_cycle)
        
        def regen_cycle(self):
            if (not self.regenerating or self.god or
                self.world_object is None or self.world_object.dead):
                self.regen_loop.stop()
                return
            last_hit = self.last_hit
            if last_hit and reactor.seconds() - last_hit < REGEN_ONSET:
                return
            if self.hp < 100 - REGEN_AMOUNT:
                self.set_hp(self.hp + REGEN_AMOUNT, type = FALL_KILL)
            else:
                self.refill()
                self.regen_loop.stop()
        
        def get_spawn_location(self):
            if self.protocol.boss and self.world_object and not self.trapped:
                return self.world_object.position.get()
            return connection.get_spawn_location(self)
        
        def get_respawn_time(self):
            if self.protocol.boss:
                return 2 if self.trapped else RESPAWN_TIME
            return connection.get_respawn_time(self)
        
        def on_spawn(self, pos):
            if self.trapped:
                self.send_chat('You were eaten by a giant squid :( Pray your '
                    'friends can get you out of this one.')
                self.set_location(self.protocol.boss.origin.get())
            return connection.on_spawn(self, pos)
        
        def on_reset(self):
            self.regenerating = False
            self.trapped = False
            self.got_water_damage = False
            self.grabbed_by = None
            self.last_hit = None
            if self.regen_loop and self.regen_loop.running:
                self.regen_loop.stop()
            connection.on_reset(self)
        
        def on_disconnect(self):
            if self.regen_loop and self.regen_loop.running:
                self.regen_loop.stop()
            self.regen_loop = None
            connection.on_disconnect(self)
        
        def on_kill(self, killer, type, grenade):
            if self.protocol.boss:
                if self.grabbed_by:
                    self.grabbed_by.grabbed_player = None
                self.grabbed_by = None
                if (self.trapped or self.got_water_damage and 
                    self.protocol.boss and not self.protocol.boss.dead and
                    self.protocol.boss.head):
                    self.trapped = True
                else:
                    self.send_chat('You died! Yell at your friends to walk '
                        'over you to revive you.')
            connection.on_kill(self, killer, type, grenade)
        
        def on_weapon_set(self, value):
            if self.protocol.boss and self.regenerating:
                self.weapon = value
                self.set_weapon(self.weapon, no_kill = True)
                self.spawn(self.world_object.position.get())
                return False
            return connection.on_weapon_set(self, value)
        
        def on_orientation_update(self, x, y, z):
            if self.protocol.hp_bar and self.protocol.hp_bar.shown:
                self.protocol.hp_bar.update_for_player(self, (x, y, z))
            connection.on_orientation_update(self, x, y, z)
        
        def on_position_update(self):
            if not self.protocol.boss_ready:
                connection.on_position_update(self)
                return
            if is_valid_enemy(self) and self.world_object.position.z >= 61:
                self.got_water_damage = True
                self.hit(WATER_DAMAGE)
                self.got_water_damage = False
            if (not self.world_object.dead and not self.grabbed_by
                and not self.trapped):
                for player in self.protocol.players.values():
                    if player is not self and player.world_object.dead:
                        pos = player.world_object.position
                        if vector_collision(self.world_object.position, pos):
                            player.spawn(pos.get())
            if self.protocol.hp_bar and self.protocol.hp_bar.shown:
                self.protocol.hp_bar.update_for_player(self)
            connection.on_position_update(self)
        
        def on_block_build_attempt(self, x, y, z):
            if self.trapped:
                return False
            return connection.on_block_build(self, x, y, z)
        
        def on_block_destroy(self, x, y, z, mode):
            if self.trapped or self.grabbed_by:
                return False
            if self.protocol.boss:
                if self.protocol.boss.on_block_destroy(x, y, z, mode) == False:
                    return False
            return connection.on_block_destroy(self, x, y, z, mode)
        
        def on_block_removed(self, x, y, z):
            if self.protocol.boss:
                self.protocol.boss.on_block_removed(x, y, z)
            connection.on_block_removed(self, x, y, z)
        
        def on_hit(self, hit_amount, player, type, grenade):
            self.last_hit = reactor.seconds()
            if self.regenerating and not self.regen_loop.running:
                self.regen_loop.start(REGEN_FREQUENCY)
            if self.protocol.boss_ready:
                if self is player and self.hp:
                    if hit_amount >= self.hp:
                        return self.hp - 1
            return connection.on_hit(self, hit_amount, player, type, grenade)

        def on_kill(self, killer, type, grenade):
            if not killer or self==killer:
                return connection.on_kill(self,killer,type,grenade)
            return False
        
        def on_fall(self, damage):
            if self.grabbed_by or self.regenerating:
                return False
            self.last_hit = reactor.seconds()
            if self.regenerating and not self.regen_loop.running:
                self.regen_loop.start(REGEN_FREQUENCY)
            return connection.on_fall(self, damage)
    
    return BossProtocol, BossConnection

Attachments
kraken.py
Put in scripts folder
(43.99 KiB) Downloaded 301 times
Last edited by thepolm3 on Sun Aug 11, 2013 7:44 pm, edited 3 times in total.
rakiru
Coder
Coder
Posts: 1349
Joined: Sun Nov 11, 2012 12:26 pm


What exactly did you fix? Other than changing the colour format for no apparent reason, and slightly changing a couple lines of code, there are no changes. I'm not saying you didn't fix anything, I'm just wondering what you fixed specifically. I assume removing the check if a block existed was to fix ghost blocks, but that seems a somewhat hacky workaround.

Edit: Just realised a lot of the small changes (including the colour code) was already different in the version you were working on compared to the one I've got.
thepolm3
Scripter
Scripter
Posts: 424
Joined: Sat Feb 16, 2013 10:49 pm


rakiru wrote:
What exactly did you fix? Other than changing the colour format for no apparent reason, and slightly changing a couple lines of code, there are no changes. I'm not saying you didn't fix anything, I'm just wondering what you fixed specifically. I assume removing the check if a block existed was to fix ghost blocks, but that seems a somewhat hacky workaround.

Edit: Just realised a lot of the small changes (including the colour code) was already different in the version you were working on compared to the one I've got.
It's quite a closed and complete script, all it needed were some small changes. Thats why I plan on rewriting it.
rakiru
Coder
Coder
Posts: 1349
Joined: Sun Nov 11, 2012 12:26 pm


thepolm3 wrote:
rakiru wrote:
What exactly did you fix? Other than changing the colour format for no apparent reason, and slightly changing a couple lines of code, there are no changes. I'm not saying you didn't fix anything, I'm just wondering what you fixed specifically. I assume removing the check if a block existed was to fix ghost blocks, but that seems a somewhat hacky workaround.

Edit: Just realised a lot of the small changes (including the colour code) was already different in the version you were working on compared to the one I've got.
It's quite a closed and complete script, all it needed were some small changes. Thats why I plan on rewriting it.
Yes, but what did those changes do, is what I'm asking. I've never had a problem running it on 0.75, so I have no idea what you fixed.
thepolm3
Scripter
Scripter
Posts: 424
Joined: Sat Feb 16, 2013 10:49 pm


BTW I meant 0.76 when I said 0.75 (I did mean 0.75)
MAINLY I fixed 3 things
  1. Block destruction wasn't working properly; Kraken limbs didn't shrink when cut
  2. Block creation wasn't working properly; you got stuck in blocks
  3. Colour setting didn't work properly; Kraken could only be black
(and I added the fact that players can't kill each other)
like I said, no major changes, just enough so that it runs smoothly in 0.75. Sure it WORKED, but it didn't work like it did in 0.63
Hope that answers your question :)
Last edited by thepolm3 on Sun Aug 11, 2013 8:06 pm, edited 1 time in total.
rakiru
Coder
Coder
Posts: 1349
Joined: Sun Nov 11, 2012 12:26 pm


thepolm3 wrote:
BTW I meant 0.76 when I said 0.75
MAINLY I fixed 3 things
  1. Block destruction wasn't working properly; Kraken limbs didn't shrink when cut
  2. Block creation wasn't working properly; you got stuck in blocks
  3. Colour setting didn't work properly; Kraken could only be black
(and I added the fact that players can't kill each other)
Thanks, that's what I was looking for. Stopping players killing each other is something I meant to add on my kraken server a while ago.
thepolm3 wrote:
like I said, no major changes, just enough so that it runs smoothly in 0.76. Sure it WORKED, but it didn't work like it did in 0.75
Hope that answers your question :)
I thought you meant 0.75, so when I said it worked, I was talking about that.
thepolm3
Scripter
Scripter
Posts: 424
Joined: Sat Feb 16, 2013 10:49 pm


Sorry, I was getting confused, only started playing at 0.75 so never learned the versions :)
JohnRambozo
Deuce
Posts: 10
Joined: Thu Nov 08, 2012 6:40 pm


First of all, I appreciate you making an effort but you need to know this is SO FAR from fixed. I have a feeling you never played the original working version. There are some serious problems. In fact, you actually ruined the entire thing.

Tentacles do not progress beyond the first appearance of tentacles and you somehow doubled water damage. That tells me you aren't aware of how much of the script is contained in the skullisland.txt map meta file... There is supposed to be 3 rounds of tentacles before the first 'baby' kraken appears. If you beat that one, then boulders rain from the sky killing nearly everyone. Then more rounds of more aggressive tentacles until the big mama kraken appears as the sky turns black then red (using daycycle script). You are also supposed to be able to revive teammates by standing near them.

If you beat the big kraken, then you are told to go look for another treasure. In the mountain is a crystal that releases immediate raining boulders and another baby kraken. There are then 2 full rounds of tentacles and baby krakens then the big kraken again. The entire process takes about 20 minutes if you're fighting constantly. Its very challenging even with a team of 10 - 12 people. The difficulty scales to the # of players.

Changes in the API rendered the .64 version incompatible with .75 and .76. Infogulch was able to make it partially working, but was not able to get boulders to rain, there are problems with the way water damage is handled, it does not stop doing damage once the kraken swallows you and the crystal does not start the second major wave of krakens.

I am running infogulch's partially working version at 'SuperCool Curse of Hompy Jones' this weekend on a 10 minute cycle (since round two doesn't work) if you have time to check it out.

Thanks.
John Rambozo
JohnRambozo
Deuce
Posts: 10
Joined: Thu Nov 08, 2012 6:40 pm


Oh and those complaining about the two teams. You just use the admin command "/lock green" and all is solved with that.
JohnRambozo
Deuce
Posts: 10
Joined: Thu Nov 08, 2012 6:40 pm


And one more thing. If you're serious about playing the Kraken game mode. I highly recommand my pirate modpack: Apart from being a pegleg pirate it also has an empty tent sprite so you don't see a tent when shooting the kraken.

Image

http://supercoolbbs.blogspot.com/2012/0 ... raken.html
Jdrew
Mapper
Mapper
Posts: 4808
Joined: Tue Oct 30, 2012 10:48 pm


Why does it have to have all that?
Kuma
Scripter
Scripter
Posts: 758
Joined: Fri Mar 22, 2013 10:05 am


umm, because it had all that.
MKU
Artist
Artist
Posts: 383
Joined: Wed Oct 31, 2012 12:20 am


What JohnRambozo just explained is how the original Kraken mode was. Now, Jdrew, what I see is 2703 posts of your's that don't help or contribute to anyone.
TimeToDie
Green Master Race
Green Master Race
Posts: 37
Joined: Tue Sep 17, 2013 3:52 pm


So this script still have bugs and problems that make him not working or it all fixed ?
MKU
Artist
Artist
Posts: 383
Joined: Wed Oct 31, 2012 12:20 am


idantheking99 wrote:
So this script still have bugs and problems that make him not working or it all fixed ?
This is nothing like the original, I recommend you don't waste your time.
18 posts Page 1 of 2
Return to “Work In Progress”

Who is online

Users browsing this forum: No registered users and 1 guest