Example #1
0
Iscript::CmdResult Image::ConstIscriptCommand(Iscript::Context *ctx, Iscript::Script *script,
                                              const Iscript::Command &cmd) const
{
    using namespace Iscript::Opcode;
    using Iscript::CmdResult;
    switch (cmd.opcode)
    {
        case Goto:
            script->pos = cmd.pos;
        break;
        case Call:
            script->return_pos = script->pos;
            script->pos = cmd.pos;
        break;
        case Return:
            script->pos = script->return_pos;
        break;
        case RandCondJmp:
            if (cmd.val > ctx->rng->Rand(256))
                script->pos = cmd.pos;
        break;
        case Wait:
            script->wait = cmd.val - 1;
            return CmdResult::Stop;
        break;
        case WaitRand:
            script->wait = cmd.val1() + ctx->rng->Rand(cmd.val2() - cmd.val1() + 1);
            return CmdResult::Stop;
        break;
        case End:
            // This generally gets handled by sprite, but needs to be doen here as well
            // for the speed prediction.
            return CmdResult::Stop;
        break;
        case PwrupCondJmp:
            if (parent && parent->main_image != this)
                script->pos = cmd.pos;
        break;
        default:
            return CmdResult::NotHandled;
        break;
    }
    return CmdResult::Handled;
}
Example #2
0
 virtual Iscript::CmdResult HandleCommand(Image *img, Iscript::Script *script,
         const Iscript::Command &cmd) override
 {
     auto result = img->HandleIscriptCommand(this, script, cmd);
     if (result == Iscript::CmdResult::NotHandled)
     {
         Warning("Could not handle iscript command %s for image %s from SetIscriptAnimation hook",
                 cmd.DebugStr().c_str(), img->DebugStr().c_str());
     }
     return result;
 }
Example #3
0
 virtual Iscript::CmdResult HandleCommand(Image *img, Iscript::Script *script,
                                          const Iscript::Command &cmd) override
 {
     // Firebat's attack sprite has this in normal bw, and it is
     // lone when the firebat is inside bunker.
     if (cmd.opcode == Iscript::Opcode::NoBrkCodeEnd || cmd.opcode == Iscript::Opcode::GotoRepeatAttk)
         return Iscript::CmdResult::Handled;
     Iscript::CmdResult result = sprite->HandleIscriptCommand(this, img, script, cmd);
     if (result == Iscript::CmdResult::NotHandled)
     {
         Warning("Unhandled iscript command %s in %s, image %s",
                 cmd.DebugStr().c_str(), caller, img->DebugStr().c_str());
     }
     return result;
 }
Example #4
0
bool Image::IscriptCmd(const Iscript::Command &cmd, IscriptContext *ctx, Rng *rng)
{
    using namespace IscriptOpcode;
    switch (cmd.opcode)
    {
        case PlayFram:
            if (cmd.val + direction < grp->frame_count)
                SetFrame(cmd.val);
            else
                Warning("Iscript for image %x sets image to invalid frame %x", image_id, cmd.val);
        break;
        case PlayFramTile:
            if (cmd.val + *bw::tileset < grp->frame_count)
                SetFrame(cmd.val + *bw::tileset);
        break;
        case SetHorPos:
            SetOffset(cmd.point.x, y_off);
        break;
        case SetVertPos:
            if (!ctx->unit || !ctx->unit->IsInvisible())
                SetOffset(x_off, cmd.point.y);
        break;
        case SetPos:
            SetOffset(cmd.point.x, cmd.point.y);
        break;
        case Wait:
            iscript.wait = cmd.val - 1;
        break;
        case WaitRand:
            iscript.wait = cmd.val1() + rng->Rand(cmd.val2() - cmd.val1() + 1);
        break;
        case ImgOl:
        case ImgUl:
            Iscript_AddOverlay(ctx, cmd.val, x_off + cmd.point.x, y_off + cmd.point.y, cmd.opcode == ImgOl);
        break;
        case ImgOlOrig:
        case SwitchUl:
        {
            Image *other = Iscript_AddOverlay(ctx, cmd.val, 0, 0, cmd.opcode == ImgOlOrig);
            if (other && ~other->flags & 0x80)
            {
                other->flags |= 0x80;
                SetOffsetToParentsSpecialOverlay(other);
            }
        }
        break;
        case ImgOlUseLo:
        case ImgUlUseLo:
        {
            // Yeah, it's not actually point
            Point32 point = LoFile::GetOverlay(image_id, cmd.point.x).GetValues(this, cmd.point.y);
            Iscript_AddOverlay(ctx, cmd.val, point.x + x_off, point.y + y_off, cmd.opcode == ImgOlUseLo);
        }
        break;
        case ImgUlNextId:
            Iscript_AddOverlay(ctx, image_id + 1, cmd.point.x + x_off, cmd.point.y + y_off, false);
        break;
        case SprOl:
        {
            int sprite_id = cmd.val;
            if (ctx->bullet && ctx->bullet->parent && ctx->bullet->parent->IsGoliath())
            {
                Unit *goliath = ctx->bullet->parent;
                if (GetUpgradeLevel(Upgrade::CharonBooster, goliath->player) ||
                        (units_dat_flags[goliath->unit_id] & UnitFlags::Hero && *bw::is_bw))
                {
                    sprite_id = Sprite::HaloRocketsTrail;
                }
            }
            Sprite::Spawn(this, sprite_id, cmd.point, parent->elevation + 1);
        }
        break;
        case HighSprOl:
            Sprite::Spawn(this, cmd.val, cmd.point, parent->elevation - 1);
        break;
        case LowSprUl:
            Sprite::Spawn(this, cmd.val, cmd.point, 1);
        break;
        case UflUnstable:
        {
            Warning("Flingy creation not implemented (image %x)", image_id);
            /*Flingy *flingy = CreateFlingy(cmd.val, parent->player, cmd.point);
            if (flingy)
            {
                flingy->GiveRandomMoveTarget(rng);
                flingy->sprite->UpdateVisibilityPoint();
            }*/
        }
        break;
        case SprUlUseLo:
        case SprUl:
        {
            int elevation = parent->elevation;
            if (cmd.opcode == SprUl)
                elevation -= 1;
            if (!ctx->unit || !ctx->unit->IsInvisible() || images_dat_draw_if_cloaked[cmd.val])
            {
                Sprite *sprite = Sprite::Spawn(this, cmd.val, cmd.point, elevation);
                if (sprite)
                {
                    if (flags & 0x2)
                        sprite->SetDirection32(32 - direction);
                    else
                        sprite->SetDirection32(direction);
                }
            }
        }
        break;
        case SprOlUseLo:
        {
            // Again using the "point" for additional storage
            Point32 point = LoFile::GetOverlay(image_id, cmd.point.x).GetValues(this, 0);
            Sprite *sprite = Sprite::Spawn(this, cmd.val, point.ToPoint16(), parent->elevation + 1);
            if (sprite)
            {
                if (flags & 0x2)
                    sprite->SetDirection32(32 - direction);
                else
                    sprite->SetDirection32(direction);
            }
        }
        break;
        case SetFlipState:
            SetFlipping(cmd.val);
        break;
        case PlaySnd:
            PlaySoundAtPos(cmd.val, parent->position.AsDword(), 1, 0);
        break;
        case PlaySndRand:
        {
            int num = rng->Rand(cmd.data[0]);
            int sound = *(uint16_t *)(cmd.data + 1 + num * 2);
            PlaySoundAtPos(sound, parent->position.AsDword(), 1, 0);
        }
        break;
        case PlaySndBtwn:
        {
            int num = rng->Rand(cmd.val2() - cmd.val1() + 1);
            PlaySoundAtPos(cmd.val1() + num, parent->position.AsDword(), 1, 0);
        }
        break;
        case FollowMainGraphic:
            if (parent->main_image)
            {
                Image *main_img = parent->main_image;
                if (main_img->frame != frame || (main_img->flags & 0x2) != (flags & 0x2))
                {
                    int new_frame = main_img->frameset + main_img->direction;
                    if (new_frame >= grp->frame_count)
                        Warning("Iscript for image %x requested to play frame %x with followmaingraphic", image_id, new_frame);
                    else
                    {
                        frameset = main_img->frameset;
                        direction = main_img->direction;
                        SetFlipping(main_img->flags & 0x2);
                        UpdateFrameToDirection();
                    }
                }
            }
        break;
        case TurnCcWise:
        case TurnCWise:
        case Turn1CWise:
        {
            Flingy *entity = ctx->unit != nullptr ? (Flingy *)ctx->unit : (Flingy *)ctx->bullet;
            int direction = 1;
            if (cmd.opcode == TurnCcWise)
                direction = 0 - cmd.val;
            else if (cmd.opcode == TurnCWise)
                direction = cmd.val;
            SetDirection(entity, entity->facing_direction + direction * 8);
        }
        break;
        case SetFlDirect:
        {
            Flingy *entity = ctx->unit != nullptr ? (Flingy *)ctx->unit : (Flingy *)ctx->bullet;
            SetDirection(entity, cmd.val * 8);
        }
        break;
        case TurnRand:
        {
            Flingy *entity = ctx->unit != nullptr ? (Flingy *)ctx->unit : (Flingy *)ctx->bullet;
            int num = rng->Rand(4);
            if (num == 0)
                SetDirection(entity, entity->facing_direction - cmd.val * 8);
            else
                SetDirection(entity, entity->facing_direction + cmd.val * 8);
        }
        break;
        case SetSpawnFrame:
            SetMoveTargetToNearbyPoint(cmd.val, ctx->unit);
        break;
        case SigOrder:
        case OrderDone:
        {
            Unit *entity = ctx->unit != nullptr ? ctx->unit : (Unit *)ctx->bullet;
            if (cmd.opcode == SigOrder)
                entity->order_signal |= cmd.val;
            else
                entity->order_signal &= ~cmd.val;
        }
        break;
        case AttackWith:
            Iscript_AttackWith(ctx->unit, cmd.val);
        break;
        case Attack:
            if (!ctx->unit->target || ctx->unit->target->IsFlying())
                Iscript_AttackWith(ctx->unit, 0);
            else
                Iscript_AttackWith(ctx->unit, 1);
        break;
        case CastSpell:
            if (orders_dat_targeting_weapon[ctx->unit->order] != Weapon::None && !ShouldStopOrderedSpell(ctx->unit))
                FireWeapon(ctx->unit, orders_dat_targeting_weapon[ctx->unit->order]);
        break;
        case UseWeapon:
            Iscript_UseWeapon(cmd.val, ctx->unit);
        break;
        case GotoRepeatAttk:
            if (ctx->unit)
                ctx->unit->flingy_flags &= ~0x8;
        break;
        case EngFrame:
            frameset = cmd.val;
            direction = parent->main_image->direction;
            SetFlipping(parent->main_image->IsFlipped());
            UpdateFrameToDirection();
        break;
        case EngSet:
            frameset = parent->main_image->frameset + parent->main_image->grp->frame_count * cmd.val;
            direction = parent->main_image->direction;
            SetFlipping(parent->main_image->IsFlipped());
            UpdateFrameToDirection();
        break;
        case HideCursorMarker:
            *bw::draw_cursor_marker = 0;
        break;
        case NoBrkCodeStart:
            ctx->unit->flags |= UnitStatus::Nobrkcodestart;
            ctx->unit->sprite->flags |= 0x80;
        break;
        case NoBrkCodeEnd:
        if (ctx->unit)
        {
            ctx->unit->flags &= ~UnitStatus::Nobrkcodestart;
            ctx->unit->sprite->flags &= ~0x80;
            if (ctx->unit->order_queue_begin && ctx->unit->order_flags & 0x1)
            {
                ctx->unit->IscriptToIdle();
                ctx->unit->DoNextQueuedOrder();
            }
        }
        // This actually is feature ._. bunkers can create lone flamethrower sprites
        // whose default iscript has nobreakcodeend
        //else
            //Warning("Iscript for image %x used nobrkcodeend without having unit", image_id);
        break;
        case IgnoreRest:
            if (ctx->unit->target == nullptr)
                ctx->unit->IscriptToIdle();
            else
            {
                iscript.wait = 10;
                iscript.pos -= cmd.Size(); // Loop on this cmd
            }
        break;
        case AttkShiftProj:
            // Sigh
            weapons_dat_x_offset[ctx->unit->GetGroundWeapon()] = cmd.val;
            Iscript_AttackWith(ctx->unit, 1);
        break;
        case TmpRmGraphicStart:
            Hide();
        break;
        case TmpRmGraphicEnd:
            Show();
        break;
        case SetFlSpeed:
            ctx->unit->flingy_top_speed = cmd.val;
        break;
        case CreateGasOverlays:
        {
            Image *img = Allocate();
            if (parent->first_overlay == this)
            {
                Assert(list.prev == nullptr);
                parent->first_overlay = img;
            }
            img->list.prev = list.prev;
            img->list.next = this;
            if (list.prev)
                list.prev->list.next = img;
            list.prev = img;
            int smoke_img = VespeneSmokeOverlay1 + cmd.val;
            // Bw can be misused to have this check for loaded nuke and such
            // Even though resource_amount is word, it won't report incorrect values as unit array starts from 0x0059CCA8
            // (The lower word is never 0 if the union contains unit)
            // But with dynamic allocation, that is not the case
            if (units_dat_flags[ctx->unit->unit_id] & UnitFlags::ResourceContainer)
            {
                if (ctx->unit->building.resource.resource_amount == 0)
                    smoke_img = VespeneSmallSmoke1 + cmd.val;
            }
            else
            {
                if (ctx->unit->building.silo.nuke == nullptr)
                    smoke_img = VespeneSmallSmoke1 + cmd.val;
            }
            Point pos = LoFile::GetOverlay(image_id, Overlay::Special).GetValues(this, cmd.val).ToPoint16();
            InitializeImageFull(smoke_img, img, pos.x + x_off, pos.y + y_off, parent);
        }
        break;
        case WarpOverlay:
            flags |= 0x1;
            drawfunc_param = (void *)cmd.val;
        break;
        case GrdSprOl:
        {
            int x = parent->position.x + x_off + cmd.point.x;
            int y = parent->position.y + y_off + cmd.point.y;
            // Yes, it checks if unit id 0 can fit there
            if (DoesFitHere(Unit::Marine, x, y))
                Sprite::Spawn(this, cmd.val, cmd.point, parent->elevation + 1);
        }
        break;
        default:
            return false;
    }
    return true;
}
Example #5
0
Iscript::CmdResult Image::HandleIscriptCommand(Iscript::Context *ctx, Iscript::Script *script,
                                               const Iscript::Command &cmd)
{
    using namespace Iscript::Opcode;
    switch (cmd.opcode)
    {
        case PlayFram:
            if (cmd.val + direction < grp->frame_count)
                SetFrame(cmd.val);
            else
                Warning("Iscript for image %s sets image to invalid frame %x", DebugStr().c_str(), cmd.val);
        break;
        case PlayFramTile:
            if (cmd.val + *bw::tileset < grp->frame_count)
                SetFrame(cmd.val + *bw::tileset);
        break;
        case SetHorPos:
            SetOffset(cmd.point.x, y_off);
        break;
        case SetVertPos:
            SetOffset(x_off, cmd.point.y);
        break;
        case SetPos:
            SetOffset(cmd.point.x, cmd.point.y);
        break;
        case ImgOl:
            Iscript_AddOverlay(ctx, cmd.val, x_off + cmd.point.x, y_off + cmd.point.y, true);
        break;
        case ImgUl:
            Iscript_AddOverlay(ctx, cmd.val, x_off + cmd.point.x, y_off + cmd.point.y, false);
        break;
        case ImgOlOrig:
        case SwitchUl:
        {
            Image *other = Iscript_AddOverlay(ctx, cmd.val, 0, 0, cmd.opcode == ImgOlOrig);
            if (other != nullptr && ~other->flags & ImageFlags::UseParentLo)
            {
                other->flags |= ImageFlags::UseParentLo;
                SetOffsetToParentsSpecialOverlay(other);
            }
        }
        break;
        case ImgOlUseLo:
        case ImgUlUseLo:
        {
            // Yeah, it's not actually point
            Point32 point = LoFile::GetOverlay(image_id, cmd.point.x).GetValues(this, cmd.point.y);
            Iscript_AddOverlay(ctx, cmd.val, point.x + x_off, point.y + y_off, cmd.opcode == ImgOlUseLo);
        }
        break;
        case ImgUlNextId:
            Iscript_AddOverlay(ctx, image_id + 1, cmd.point.x + x_off, cmd.point.y + y_off, false);
        break;
        case SprOl:
            // Bullet's iscript handler has an override for goliath range upgrade
            Sprite::Spawn(this, cmd.val, cmd.point, parent->elevation + 1);
        break;
        case HighSprOl:
            Sprite::Spawn(this, cmd.val, cmd.point, parent->elevation - 1);
        break;
        case LowSprUl:
            Sprite::Spawn(this, cmd.val, cmd.point, 1);
        break;
        case UflUnstable:
        {
            Warning("Flingy creation not implemented (image %s)", DebugStr().c_str());
            /*Flingy *flingy = CreateFlingy(cmd.val, parent->player, cmd.point);
            if (flingy)
            {
                flingy->GiveRandomMoveTarget(ctx->rng);
                flingy->sprite->UpdateVisibilityPoint();
            }*/
        }
        break;
        case SprUlUseLo:
        case SprUl:
        {
            int elevation = parent->elevation;
            if (cmd.opcode == SprUl)
                elevation -= 1;
            Sprite *sprite = Sprite::Spawn(this, cmd.val, cmd.point, elevation);
            if (sprite != nullptr)
            {
                if (IsFlipped())
                    sprite->SetDirection32(32 - direction);
                else
                    sprite->SetDirection32(direction);
            }
        }
        break;
        case SprOlUseLo:
        {
            // Again using the "point" for additional storage
            Point32 point = LoFile::GetOverlay(image_id, cmd.point.x).GetValues(this, 0);
            Sprite *sprite = Sprite::Spawn(this, cmd.val, point.ToPoint16(), parent->elevation + 1);
            if (sprite)
            {
                if (IsFlipped())
                    sprite->SetDirection32(32 - direction);
                else
                    sprite->SetDirection32(direction);
            }
        }
        break;
        case SetFlipState:
            SetFlipping(cmd.val);
        break;
        case PlaySnd:
        case PlaySndRand:
        case PlaySndBtwn:
        {
            int sound_id;
            if (cmd.opcode == PlaySnd)
                sound_id = cmd.val;
            else if (cmd.opcode == PlaySndRand)
                sound_id = *(uint16_t *)(cmd.data + 1 + ctx->rng->Rand(cmd.data[0]) * 2);
            else // PlaySndBtwn
                sound_id = cmd.val1() + ctx->rng->Rand(cmd.val2() - cmd.val1() + 1);
            PlaySoundAtPos(sound_id, parent->position.AsDword(), 1, 0);
        }
        break;
        case FollowMainGraphic:
            if (parent->main_image != nullptr)
            {
                Image *main_img = parent->main_image;
                if (main_img->frame != frame || main_img->IsFlipped() != IsFlipped())
                {
                    int new_frame = main_img->frameset + main_img->direction;
                    if (new_frame >= grp->frame_count)
                    {
                        Warning("Iscript for image %s requested to play frame %x with followmaingraphic",
                                DebugStr().c_str(), new_frame);
                    }
                    else
                    {
                        frameset = main_img->frameset;
                        FollowMainImage();
                    }
                }
            }
        break;
        case EngFrame:
        case EngSet:
            if (cmd.opcode == EngFrame)
                frameset = cmd.val;
            else // EndSet
                frameset = parent->main_image->frameset + parent->main_image->grp->frame_count * cmd.val;
            FollowMainImage();
        break;
        case HideCursorMarker:
            *bw::draw_cursor_marker = 0;
        break;
        case TmpRmGraphicStart:
            Hide();
        break;
        case TmpRmGraphicEnd:
            Show();
        break;
        case WarpOverlay:
            flags |= ImageFlags::Redraw;
            drawfunc_param = (void *)cmd.val;
        break;
        case GrdSprOl:
        {
            int x = parent->position.x + x_off + cmd.point.x;
            int y = parent->position.y + y_off + cmd.point.y;
            // Yes, it checks if unit id 0 can fit there
            if (DoesFitHere(Unit::Marine, x, y))
                Sprite::Spawn(this, cmd.val, cmd.point, parent->elevation + 1);
        }
        break;
        default:
            return ConstIscriptCommand(ctx, script, cmd);
        break;
    }
    return Iscript::CmdResult::Handled;
}