/** * @param TES4CodeBlock $block * @param TES5EventBlockList $blockList * @param TES5EventCodeBlock $newBlock * @param TES5MultipleScriptsScope $multipleScriptsScope * @param TES5GlobalScope $globalScope */ public function modify(TES4CodeBlock $block, TES5EventBlockList $blockList, TES5EventCodeBlock $newBlock, TES5GlobalScope $globalScope, TES5MultipleScriptsScope $multipleScriptsScope) { $blockLocalScope = $newBlock->getLocalScope(); switch (strtolower($block->getBlockType())) { case "gamemode": case 'scripteffectupdate': $onInitLocalScope = $this->blockLocalScopeFactory->createFromBlockType("OnInit", $globalScope); $newInitBlock = new TES5EventCodeBlock("OnInit", $onInitLocalScope, $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($onInitLocalScope))); $args = new TES5ObjectCallArguments(); $args->add(new TES5Float(self::ON_UPDATE_TICK)); $function = $this->valueFactory->createObjectCall($this->referenceFactory->createReferenceToSelf($globalScope), "RegisterForUpdate", $multipleScriptsScope, $args); $newInitBlock->addChunk($function); $blockList->add($newInitBlock); break; case "onactivate": $onInitLocalScope = $this->blockLocalScopeFactory->createFromBlockType("OnInit", $globalScope); $newInitBlock = new TES5EventCodeBlock("OnInit", $onInitLocalScope, $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($onInitLocalScope))); $function = $this->valueFactory->createObjectCall($this->referenceFactory->createReferenceToSelf($globalScope), "BlockActivation", $multipleScriptsScope); $newInitBlock->addChunk($function); $blockList->add($newInitBlock); break; case 'onactorequip': $parameterList = $block->getBlockParameterList(); if ($parameterList == null) { break; } $parameterList = $parameterList->getVariableList(); $tesEquippedTarget = $parameterList[0]; $localScope = $newBlock->getCodeScope()->getLocalScope(); $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope); $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->findVariableWithMeaning(TES5LocalVariableParameterMeaning::CONTAINER())), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer); $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope)); $outerBranchCode = unserialize(serialize($newBlock->getCodeScope())); $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope()); $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode))); $newBlock->setCodeScope($newCodeScope); break; case "ontriggeractor": $parameterList = $block->getBlockParameterList(); $localScope = $newBlock->getCodeScope()->getLocalScope(); $activator = $localScope->findVariableWithMeaning(TES5LocalVariableParameterMeaning::ACTIVATOR()); $castedToActor = new TES5LocalVariable("akAsActor", TES5BasicType::T_ACTOR()); $referenceToCastedVariable = $this->referenceFactory->createReferenceToVariable($castedToActor); $referenceToNonCastedVariable = $this->referenceFactory->createReferenceToVariable($activator); $expression = $this->expressionFactory->createArithmeticExpression($referenceToCastedVariable, TES5ArithmeticExpressionOperator::OPERATOR_NOT_EQUAL(), new TES5None()); $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope)); $newCodeScope->getLocalScope()->addVariable($castedToActor); $newCodeScope->add($this->assignationFactory->createAssignation($referenceToCastedVariable, $referenceToNonCastedVariable)); if ($parameterList !== null) { //NOT TESTED $parameterList = $parameterList->getVariableList(); $targetActor = $this->valueFactory->createReadReference($parameterList[0]->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope); $interExpression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($activator), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $targetActor); $interBranchCode = unserialize(serialize($newBlock->getCodeScope())); $outerBranchCode = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($newCodeScope->getLocalScope())); $interBranchCode->getLocalScope()->setParentScope($outerBranchCode->getLocalScope()); $outerBranchCode->add(new TES5Branch(new TES5SubBranch($interExpression, $interBranchCode))); } else { $outerBranchCode = unserialize(serialize($newBlock->getCodeScope())); $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope()); } $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode))); $newBlock->setCodeScope($newCodeScope); break; case 'onadd': $parameterList = $block->getBlockParameterList(); if ($parameterList == null) { break; } $parameterList = $parameterList->getVariableList(); $tesEquippedTarget = $parameterList[0]; $localScope = $newBlock->getCodeScope()->getLocalScope(); $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope); $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->getVariableByName("akNewContainer")), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer); $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope)); $outerBranchCode = unserialize(serialize($newBlock->getCodeScope())); $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope()); $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode))); $newBlock->setCodeScope($newCodeScope); break; case 'ondrop': $parameterList = $block->getBlockParameterList(); if ($parameterList == null) { break; } $parameterList = $parameterList->getVariableList(); $tesEquippedTarget = $parameterList[0]; $localScope = $newBlock->getCodeScope()->getLocalScope(); $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope); $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->getVariableByName("akOldContainer")), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer); $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope)); $outerBranchCode = unserialize(serialize($newBlock->getCodeScope())); $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope()); $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode))); $newBlock->setCodeScope($newCodeScope); break; case 'onpackagestart': $parameterList = $block->getBlockParameterList(); if ($parameterList == null) { break; } $parameterList = $parameterList->getVariableList(); $tesEquippedTarget = $parameterList[0]; $localScope = $newBlock->getCodeScope()->getLocalScope(); $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope); $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->getVariableByName("akNewPackage")), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer); $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope)); $outerBranchCode = unserialize(serialize($newBlock->getCodeScope())); $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope()); $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode))); $newBlock->setCodeScope($newCodeScope); break; case 'onpackagedone': case 'onpackagechange': case 'onpackageend': $parameterList = $block->getBlockParameterList()->getVariableList(); $tesEquippedTarget = $parameterList[0]; $localScope = $newBlock->getCodeScope()->getLocalScope(); $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope); $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->getVariableByName("akOldPackage")), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer); $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope)); $outerBranchCode = unserialize(serialize($newBlock->getCodeScope())); $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope()); $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode))); $newBlock->setCodeScope($newCodeScope); break; case 'onalarm': //@INCONSISTENCE - We don't account for alarm type. $expression = $this->expressionFactory->createArithmeticExpression($this->valueFactory->createObjectCall($this->referenceFactory->createReferenceToSelf($globalScope), "IsAlarmed", $multipleScriptsScope), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), new TES5Bool(true)); $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope)); $outerBranchCode = unserialize(serialize($newBlock->getCodeScope())); $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope()); $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode))); $newBlock->setCodeScope($newCodeScope); break; /** case 'onalarm': { $this->skyrimGroupEventName = 'onhit'; if ($this->eventArgs[1] != 3) { //Nothing eelse is supported really.. $this->omit = true; break; } $branch = new TES4ConditionalBranch(); $expression = new TES4Expression(); $leftConstant = new TES4Constant("akAggressor", "ObjectReference"); // $actionConstant = new TES4Constant($this->eventArgs[1],"Package"); $actionConstant = TES4Factories::createReference($this->eventArgs[2], $this); $expression->left_side = $leftConstant; $expression->right_side = $actionConstant; $expression->comparision_operator = TES4Expression::COMPARISION_OPERATOR_EQUAL; $codeBlock = new TES4CodeBlock(); $codeBlock->chunks = $this->chunks; $branch->ifs[] = array( 'rawExpression' => 'SCRIPT_GENERATED', 'expression' => $expression, 'codeBlock' => $codeBlock ); $this->chunks = new TES4ChunkContainer(); $this->chunks->parent = $this; $this->chunks->addChunk($branch); break; } */ } }
/** * @param TES4ScriptCollection $scripts * @return TES5ScriptCollection * @throws ConversionException */ public function convert(TES4ScriptCollection $scripts) { $transpiledCollection = new TES5ScriptCollection(); $scriptHeaders = []; $globalScopes = []; /** * @var TES4Target $scriptTarget */ foreach ($scripts->getIterator() as $k => $scriptTarget) { $script = $scriptTarget->getScript(); //Create the header. $scriptHeader = $this->createHeader($script); $variableList = $script->getVariableDeclarationList(); $globalScope = new TES5GlobalScope($scriptHeader); foreach ($this->esmAnalyzer->getGlobalVariables() as $globalVariable) { $globalScope->addGlobalVariable($globalVariable); } if ($variableList !== null) { $this->propertiesFactory->createProperties($variableList, $globalScope); } $scriptHeaders[$k] = $scriptHeader; $globalScopes[$k] = $globalScope; } //Add the static global scopes which are added by complimenting scripts.. $staticGlobalScopes = $this->staticGlobalScopesFactory->createGlobalScopes(); foreach ($staticGlobalScopes as $staticGlobalScope) { $globalScopes[] = $staticGlobalScope; } $multipleScriptsScope = new TES5MultipleScriptsScope($globalScopes); /** * @var TES4Target $scriptTarget */ foreach ($scripts->getIterator() as $k => $scriptTarget) { $scriptHeader = $scriptHeaders[$k]; $globalScope = $globalScopes[$k]; $script = $scriptTarget->getScript(); $blockList = new TES5BlockList(); $parsedBlockList = $script->getBlockList(); $createdBlocks = []; if ($parsedBlockList !== null) { foreach ($parsedBlockList->getBlocks() as $block) { $newBlockList = $this->blockFactory->createBlock($multipleScriptsScope, $globalScope, $block); foreach ($newBlockList->getBlocks() as $newBlock) { if (!isset($createdBlocks[$newBlock->getBlockType()])) { $createdBlocks[$newBlock->getBlockType()] = []; } $createdBlocks[$newBlock->getBlockType()][] = $newBlock; } } } //todo encapsulate it to a different class. foreach ($createdBlocks as $blockType => $blocks) { if (count($blocks) > 1) { /** * @var TES5FunctionCodeBlock[] $functions */ $functions = []; $i = 1; $localScopeArguments = null; /** * @var TES5EventCodeBlock $block */ foreach ($blocks as $block) { $function = new TES5FunctionCodeBlock($blockType . "_" . $i, null, $block->getLocalScope(), $block->getCodeScope()); $functions[] = $function; if ($localScopeArguments === null) { $localScopeArguments = new TES5ObjectCallArguments(); foreach ($block->getLocalScope()->getLocalVariables() as $localVariable) { $localScopeArguments->add($this->referenceFactory->createReferenceToVariable($localVariable)); } } ++$i; } //Create the proxy block. $proxyBlock = $this->blockFactory->createNewBlock($blockType, clone $block->getLocalScope()); foreach ($functions as $function) { $blockList->add($function); $functionCall = $this->valueFactory->createObjectCall($this->referenceFactory->createReferenceToSelf($globalScope), $function->getFunctionName(), $multipleScriptsScope, $localScopeArguments, false); $proxyBlock->addChunk($functionCall); } $blockList->add($proxyBlock); } else { $block = current($blocks); $blockList->add($block); } } $tesScript = new TES5Script($scriptHeader, $globalScope, $blockList); $transpiledCollection->add($tesScript, $scriptTarget->getOutputPath()); } return $transpiledCollection; }