Downloads containing SEweapon.asc

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Facilis descensus AvernoFeatured Download Loon Battle 8.5 Download file

File preview

namespace se {
funcdef void MainCallback(int number);
funcdef void PlayerCallback(::jjPLAYER@ player, int number);
funcdef bool DrawingCallback(::jjPLAYER@ player, ::jjCANVAS@ canvas, const ::jjANIMATION@ anim);
funcdef void PacketCallback(::jjSTREAM& packet, int clientID);
funcdef ::jjSTREAM PacketConstructor();
shared enum WeaponTrait {
        weapon_no_trait                         = 0,
        weapon_deals_damage                     = 1 << 0,
        weapon_causes_splash_damage             = 1 << 1,
        weapon_may_harm_user                    = 1 << 2,
        weapon_may_heal_players                 = 1 << 3,
        weapon_increases_mobility               = 1 << 4,
        weapon_inflicts_status_condition        = 1 << 5,
        weapon_melts_ice                        = 1 << 6,
        weapon_freezes_objects                  = 1 << 7,
        weapon_fails_underwater                 = 1 << 8,
        weapon_fails_in_interiors               = 1 << 9,
        weapon_goes_through_thin_walls          = 1 << 10,
        weapon_goes_through_thick_walls         = 1 << 11,
        weapon_is_super_weapon                  = 1 << 12,
        weapon_is_effective_against_players     = 1 << 13,
        weapon_is_effective_against_sp_enemies  = 1 << 14,
        weapon_destroys_crates                  = 1 << 15,
        weapon_supports_mouse_aim               = 1 << 16,
        weapon_requires_mouse_use               = 1 << 17,
        weapon_works_in_mp                      = 1 << 18,
        weapon_works_in_sp                      = 1 << 19,
        weapon_works_in_coop                    = 1 << 20,
        weapon_works_in_splitscreen             = 1 << 21,
        weapon_works_online                     = 1 << 22,
        weapon_has_ammo_pickups                 = 1 << 23,
        weapon_has_ammo_crates                  = 1 << 24,
        weapon_has_powerup_monitors             = 1 << 25,
        weapon_has_distinct_powerup             = 1 << 26,
        weapon_requires_no_ammo_pickups         = 1 << 27,
        weapon_cannot_be_fired_by_key_press     = 1 << 28,
        weapon_requires_certain_events_in_level = 1 << 29,
        weapon_goes_through_walls               = weapon_goes_through_thin_walls | weapon_goes_through_thick_walls,
        weapon_is_effective_against_all_targets = weapon_is_effective_against_players | weapon_is_effective_against_sp_enemies | weapon_destroys_crates,
        weapon_works_in_all_modes               = weapon_works_in_mp | weapon_works_in_sp | weapon_works_in_coop | weapon_works_in_splitscreen | weapon_works_online,
        weapon_has_all_pickups                  = weapon_has_ammo_pickups | weapon_has_ammo_crates | weapon_has_powerup_monitors | weapon_has_distinct_powerup,
        weapon_default_traits                   = weapon_deals_damage | weapon_is_effective_against_all_targets | weapon_supports_mouse_aim |
                                                  weapon_works_in_all_modes | weapon_has_all_pickups
}
shared interface UserData {}
shared interface WeaponHook {
        void setUserData(uint number, UserData@ data);
        UserData@ getUserData(uint number) const;
        void setWeaponSprite(uint number, bool powerup, const ::jjANIMATION@ anim);
        void resetCallbacks(uint number);
        void setMainCallback(uint number, MainCallback@ callback);
        void setPlayerCallback(uint number, PlayerCallback@ callback);
        void setPlayerInputCallback(uint number, PlayerCallback@ callback);
        void setDrawingCallback(uint number, DrawingCallback@ callback);
        PacketConstructor@ addPacketCallback(PacketCallback@ callback);
        bool drawAmmo(::jjPLAYER@ player, ::jjCANVAS@ canvas);
        void processMain();
        void processPlayer(::jjPLAYER@ player);
        void processPlayerInput(::jjPLAYER@ player);
        bool processPacket(::jjSTREAM &in packet, int clientID);
}
shared interface WeaponInterface {
        ::jjANIMSET@ loadAnims(::jjANIMSET@ animSet);
        ::array<bool>@ loadSamples(const ::array<SOUND::Sample>& samples);
        uint getSampleCount() const;
        uint getTraits(bool powerup) const;
        uint getMaxDamage(bool powerup) const;
        bool setAsWeapon(uint number, WeaponHook@ weaponHook);
}
shared bool isValidWeapon(uint number) {
        return number != 0 && number <= WEAPON::GUN9;
}
shared uint getBasicBulletOfWeapon(uint number) {
        if (isValidWeapon(number)) {
                if (number < WEAPON::TNT)
                        return OBJECT::BLASTERBULLET + number - WEAPON::BLASTER;
                if (number > WEAPON::TNT)
                        return OBJECT::FIREBALLBULLET + number - WEAPON::GUN8;
                return OBJECT::TNT;
        }
        return 0;
}
shared uint getPoweredBulletOfWeapon(uint number) {
        if (isValidWeapon(number)) {
                if (number < WEAPON::TNT)
                        return OBJECT::BLASTERBULLETPU + number - WEAPON::BLASTER;
                if (number > WEAPON::TNT)
                        return OBJECT::FIREBALLBULLETPU + number - WEAPON::GUN8;
                return OBJECT::TNT;
        }
        return 0;
}
shared uint getAmmoPickupOfWeapon(uint number) {
        if (isValidWeapon(number) && number != WEAPON::BLASTER) {
                if (number == WEAPON::BOUNCER)
                        return OBJECT::BOUNCERAMMO3;
                if (number == WEAPON::ICE)
                        return OBJECT::ICEAMMO3;
                return OBJECT::SEEKERAMMO3 + number - WEAPON::SEEKER;
        }
        return 0;
}
shared uint getAmmoCrateOfWeapon(uint number) {
        if (number > WEAPON::BLASTER && number < WEAPON::TNT) {
                if (number == WEAPON::BOUNCER)
                        return OBJECT::BOUNCERAMMO15;
                if (number == WEAPON::ICE)
                        return OBJECT::ICEAMMO15;
                return OBJECT::SEEKERAMMO15 + number - WEAPON::SEEKER;
        }
        return 0;
}
shared uint getPowerupMonitorOfWeapon(uint number) {
        if (isValidWeapon(number)) {
                if (number < WEAPON::TNT)
                        return OBJECT::BLASTERPOWERUP + number - WEAPON::BLASTER;
                return OBJECT::TNTPOWERUP + number - WEAPON::TNT;
        }
        return 0;
}
shared class DefaultPacketConstructor {
        private ::jjSTREAM m_result;
        DefaultPacketConstructor(const ::jjSTREAM &in result) {
                m_result = result;
        }
        ::jjSTREAM opCall() const {
                return m_result;
        }
}
shared class DefaultWeaponHook : WeaponHook {
        private ::array<::array<const ::jjANIMATION@>> m_anims(9, ::array<const ::jjANIMATION@>(2));
        private ::array<UserData@> m_userData(9);
        private ::array<MainCallback@> m_mainCallbacks(9);
        private ::array<PlayerCallback@> m_playerCallbacks(9), m_playerInputCallbacks(9);
        private ::array<DrawingCallback@> m_drawingCallbacks(9);
        private ::array<PacketCallback@> m_packetCallbacks;
        private bool m_usePacketID;
        private uint8 m_packetID;
        DefaultWeaponHook() {
                m_usePacketID = false;
        }
        DefaultWeaponHook(uint8 packetID) {
                m_packetID = packetID;
                m_usePacketID = true;
        }
        void setUserData(uint number, UserData@ data) override {
                if (isValidWeapon(number))
                        @m_userData[number - 1] = @data;
        }
        UserData@ getUserData(uint number) const override {
                return isValidWeapon(number) ? @m_userData[number - 1] : null;
        }
        void setWeaponSprite(uint number, bool powerup, const ::jjANIMATION@ anim) override {
                if (isValidWeapon(number))
                        @m_anims[number - 1][powerup ? 1 : 0] = @anim;
        }
        void resetCallbacks(uint number) override {
                if (isValidWeapon(number)) {
                        number--;
                        @m_mainCallbacks[number] = null;
                        @m_playerCallbacks[number] = null;
                        @m_playerInputCallbacks[number] = null;
                        @m_drawingCallbacks[number] = null;
                }
        }
        void setMainCallback(uint number, MainCallback@ callback) override {
                if (isValidWeapon(number))
                        @m_mainCallbacks[number - 1] = @callback;
        }
        void setPlayerCallback(uint number, PlayerCallback@ callback) override {
                if (isValidWeapon(number))
                        @m_playerCallbacks[number - 1] = @callback;
        }
        void setPlayerInputCallback(uint number, PlayerCallback@ callback) override {
                if (isValidWeapon(number))
                        @m_playerInputCallbacks[number - 1] = @callback;
        }
        void setDrawingCallback(uint number, DrawingCallback@ callback) override {
                if (isValidWeapon(number))
                        @m_drawingCallbacks[number - 1] = @callback;
        }
        PacketConstructor@ addPacketCallback(PacketCallback@ callback) override {
                ::jjSTREAM packet;
                uint index = m_packetCallbacks.length();
                m_packetCallbacks.insertLast(@callback);
                if (m_usePacketID)
                        packet.push(m_packetID);
                if (index >= 0x80) {
                        packet.push(uint8(index >> 24) | 0x80);
                        packet.push(uint8(index >> 16));
                        packet.push(uint8(index >> 8));
                }
                packet.push(uint8(index));
                return @PacketConstructor(DefaultPacketConstructor(packet).opCall);
        }
        protected void drawAmmoSprite(::jjCANVAS@ canvas, int x, int y, const ::jjANIMATION@ anim) const {
                canvas.drawSpriteFromCurFrame(x, y, anim + (::jjGameTicks >> 2) % anim.frameCount);
        }
        bool drawAmmo(::jjPLAYER@ player, ::jjCANVAS@ canvas) override {
                if (player !is null) {
                        uint number = player.currWeapon;
                        if (isValidWeapon(number)) {
                                const ::jjANIMATION@ anim = @m_anims[number - 1][player.powerup[number] ? 1 : 0];
                                DrawingCallback@ callback = @m_drawingCallbacks[number - 1];
                                if (callback !is null && callback(@player, @canvas, @anim))
                                        return true;
                                if (anim !is null) {
                                        if (canvas !is null && !player.noFire && player.charCurr != CHAR::FROG && player.charCurr != CHAR::BIRD) {
                                                int x, y;
                                                STRING::Size font;
                                                ::string text;
                                                const ::jjWEAPON@ weapon = ::jjWeapons[number];
                                                if (::jjSubscreenWidth > 400) {
                                                        x = ::jjSubscreenWidth - 88;
                                                        y = ::jjSubscreenHeight - 14;
                                                        font = STRING::MEDIUM;
                                                } else {
                                                        x = ::jjSubscreenWidth - 48;
                                                        y = ::jjSubscreenHeight - 9;
                                                        font = STRING::SMALL;
                                                }
                                                if (weapon.infinite || weapon.replacedByShield && player.shieldTime > 0) {
                                                        text = "x^";
                                                } else {
                                                        int ammo = player.ammo[number];
                                                        text = "x" + (ammo > 0 ? ammo : 0);
                                                }
                                                drawAmmoSprite(@canvas, x, y, @anim);
                                                canvas.drawString(x + 8, y, text, font);
                                        }
                                        return true;
                                }
                        }
                }
                return false;
        }
        void processMain() override {
                for (int i = 0, size = m_mainCallbacks.length(); i < size; i++) {
                        if (m_mainCallbacks[i] !is null)
                                m_mainCallbacks[i](i + 1);
                }
        }
        void processPlayer(::jjPLAYER@ player) override {
                for (int i = 0, size = m_playerCallbacks.length(); i < size; i++) {
                        if (m_playerCallbacks[i] !is null)
                                m_playerCallbacks[i](@player, i + 1);
                }
        }
        void processPlayerInput(::jjPLAYER@ player) override {
                for (int i = 0, size = m_playerInputCallbacks.length(); i < size; i++) {
                        if (m_playerInputCallbacks[i] !is null)
                                m_playerInputCallbacks[i](@player, i + 1);
                }
        }
        bool processPacket(::jjSTREAM &in packet, int clientID) override {
                uint8 id, index;
                if ((!m_usePacketID || packet.pop(id) && id == m_packetID) && packet.pop(index)) {
                        uint fullIndex;
                        if (index & 0x80 != 0) {
                                index &= ~0x80;
                                uint8 u1, u2, u3;
                                if (packet.pop(u1) && packet.pop(u2) && packet.pop(u3))
                                        fullIndex = uint(index) << 24 | uint(u1) << 16 | uint(u2) << 8 | u3;
                                else
                                        fullIndex = m_packetCallbacks.length();
                        } else {
                                fullIndex = index;
                        }
                        if (fullIndex < m_packetCallbacks.length()) {
                                PacketCallback@ callback = @m_packetCallbacks[fullIndex];
                                if (callback !is null)
                                        callback(packet, clientID);
                                return true;
                        }
                }
                return false;
        }
}
shared class AmmoPickup : ::jjBEHAVIORINTERFACE {
        private const ::jjANIMATION@ m_basic, m_powered;
        private uint m_count;
        private SOUND::Sample m_sample;
        AmmoPickup(const ::jjANIMATION@ basic, const ::jjANIMATION@ powered, uint count = 3, SOUND::Sample sample = SOUND::COMMON_PICKUPW1) {
                @m_basic = @basic;
                @m_powered = @powered;
                m_count = count;
                m_sample = sample;
        }
        protected void draw(float x, float y, uint sprite, int direction, bool translucent, int playerID) const {
                ::jjDrawSpriteFromCurFrame(x, y, sprite, direction, translucent ? SPRITE::TRANSLUCENT : SPRITE::NORMAL, 0, 4, 4, playerID);
        }
        protected float getY(const ::jjOBJ@ obj) const {
                int arg = (((obj.objectID << 3) + ::jjGameTicks) << (obj.yPos > ::jjWaterLevel ? 1 : 4)) + (int(obj.xPos) << 4);
                return obj.yPos + ::jjSin(arg) * 4.f;
        }
        void setAnimationBasic(const ::jjANIMATION@ basic) {
                @m_basic = @basic;
        }
        const ::jjANIMATION@ getAnimationBasic() const {
                return @m_basic;
        }
        void setAnimationPowered(const ::jjANIMATION@ powered) {
                @m_powered = @powered;
        }
        const ::jjANIMATION@ getAnimationPowered() const {
                return @m_powered;
        }
        void setCount(uint count) {
                m_count = count;
        }
        uint getCount() const {
                return m_count;
        }
        void setSample(SOUND::Sample sample) {
                m_sample = sample;
        }
        SOUND::Sample getSample() const {
                return m_sample;
        }
        void onBehave(::jjOBJ@ obj) override {
                if (obj.state == STATE::START)
                        obj.scriptedCollisions = true;
                obj.behave(BEHAVIOR::PICKUP, false);
                for (int i = 0; i < ::jjLocalPlayerCount; i++) {
                        const ::jjPLAYER@ player = @::jjLocalPlayers[i];
                        const ::jjANIMATION@ anim = @(player.powerup[obj.var[3] + 1] ? @m_powered : @m_basic);
                        uint sprite = anim + obj.frameID % anim.frameCount;
                        draw(obj.xPos, getY(obj), sprite, obj.direction, ::jjAnimFrames[sprite].transparent, player.playerID);
                }
        }
        bool onObjectHit(::jjOBJ@ obj, ::jjOBJ@ bullet, ::jjPLAYER@ player, int) {
                if (bullet is null) {
                        bool sp = ::jjGameMode == GAME::SP || ::jjGameMode == GAME::COOP;
                        int type = obj.var[3] + 1;
                        int multiplier = ::jjWeapons[type].multiplier;
                        ::jjWeapons[type].multiplier = 1;
                        if (::jjAutoWeaponChange && player.ammo[type] == 0 && (player.shieldType == 0 || !::jjWeapons[player.currWeapon].replacedByShield) && m_count != 0)
                                player.currWeapon = type;
                        int maximum = ::jjWeapons[type].maximum;
                        if (maximum == -1)
                                maximum = sp ? 99 : 50;
                        maximum *= multiplier;
                        if (player.ammo[type] >= maximum) {
                                player.ammo[type] = maximum;
                        } else {
                                player.ammo[type] = player.ammo[type] + m_count * multiplier;
                                if (player.ammo[type] >= maximum)
                                        player.ammo[type] = maximum;
                                obj.frameID = 0;
                                obj.behavior = BEHAVIOR::EXPLOSION2;
                                ::jjSample(obj.xPos, obj.yPos, m_sample);
                                if (sp && obj.points != 0) {
                                        player.score += obj.points;
                                        ::jjPARTICLE@ part = ::jjAddParticle(PARTICLE::STRING);
                                        if (part !is null) {
                                                part.xPos = obj.xPos;
                                                part.yPos = obj.yPos;
                                                part.xSpeed = -0.5f - (jjRandom() & 0x3FFF) / 65536.f;
                                                part.ySpeed = -1.f - (jjRandom() & 0x7FFF) / 65536.f;
                                                part.string.text = ::formatInt(obj.points);
                                        }
                                        obj.points = 0;
                                }
                        }
                        ::jjWeapons[type].multiplier = multiplier;
                        return true;
                }
                return false;
        }
}
}