From: pichetp questionoptions ";print_r($question);echo "
questionoptions
";print_r($question);echo ""; if (!$question->options->answers = $DB->get_records_sql( "SELECT a.*, c.tolerance, c.tolerancetype, c.correctanswerlength, c.correctanswerformat " . @@ -318,12 +327,14 @@ class question_calculated_qtype extends default_questiontype { $state->options->dataset = $this->pick_question_dataset($question,$state->options->datasetitem); $state->responses = array('' => $regs[2]); - if ( isset($question->options->multichoice) && $question->options->multichoice == '1'){ - $virtualqtype = $this->get_virtual_qtype( $question); + $virtualqtype = $this->get_virtual_qtype( $question); + // if ( isset($question->options->multichoice) && $question->options->multichoice == '1'){ + return $virtualqtype->restore_session_and_responses($question, $state); - } - return true; + // }else { // numerical + + // return true; } function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) { @@ -364,7 +375,7 @@ class question_calculated_qtype extends default_questiontype { }; $state->options->dataset = $this->pick_question_dataset($question,$state->options->datasetitem); - $state->responses = array('' => ''); + // $state->responses = array('' => ''); if ($question->options->multichoice == 1 ) { // create an array of answerids ??? why so complicated ??? $answerids = array_values(array_map(create_function('$val', @@ -380,8 +391,12 @@ class question_calculated_qtype extends default_questiontype { } else { $state->responses = array(); } - } - return true; + return true; + } else { // numerical + $virtualqtype = $this->get_virtual_qtype( $question); + return $virtualqtype->create_session_and_responses($question, $state, $cmoptions, $attempt); + } + } function save_session_and_responses(&$question, &$state) { @@ -402,7 +417,15 @@ class question_calculated_qtype extends default_questiontype { $responses .= implode(',', $state->responses); }else { // regular numeric type - $responses .= $state->responses['']; + if(isset($state->responses['unit']) && isset($question->options->units[$state->responses['unit']])){ + $responses .= $state->responses['answer'].'|||||'.$question->options->units[$state->responses['unit']]->unit; + }else if(isset($state->responses['unit'])){ + $responses .= $state->responses['answer'].'|||||'.$state->responses['unit'] ; + }else { + $responses .= $state->responses['answer'].'|||||'; + } + + } // Set the legacy answer field @@ -732,6 +755,15 @@ class question_calculated_qtype extends default_questiontype { $DB->delete_records("question_datasets", array("question" => $questionid)); return true; } + function test_response(&$question, &$state, $answer) { + $virtualqtype = $this->get_virtual_qtype( $question); + return $virtualqtype->test_response($question, $state, $answer); + + } + function compare_responses(&$question, $state, $teststate) { + $virtualqtype = $this->get_virtual_qtype( $question); + return $virtualqtype->compare_responses($question, $state, $teststate); + } function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { // Substitute variables in questiontext before giving the data to the @@ -1897,9 +1929,9 @@ class question_calculated_qtype extends default_questiontype { fwrite ($bf,full_tag("ANSWERNUMBERING",$level+1,false,$calculated_option->answernumbering)); $status = fwrite ($bf,end_tag("CALCULATED_OPTIONS",$level,true)); } - //Now print question_answers - $status = question_backup_answers($bf,$preferences,$question); } + $status = question_backup_numerical_options($bf,$preferences,$question,$level); + } return $status; } @@ -1993,7 +2025,7 @@ class question_calculated_qtype extends default_questiontype { } //Now restore numerical_units $status = question_restore_numerical_units ($old_question_id,$new_question_id,$cal_info,$restore); - + $status = question_restore_numerical_options($old_question_id,$new_question_id,$info,$restore); //Now restore dataset_definitions if ($status && $newid) { $status = question_restore_dataset_definitions ($old_question_id,$new_question_id,$cal_info,$restore); @@ -2201,21 +2233,21 @@ function qtype_calculated_find_formula_errors($formula) { case 'is_infinite': case 'is_nan': case 'log10': case 'log1p': case 'octdec': case 'rad2deg': case 'sin': case 'sinh': case 'sqrt': case 'tan': case 'tanh': - if ($regs[4] || empty($regs[3])) { + if (!empty($regs[4]) || empty($regs[3])) { return get_string('functiontakesonearg','quiz',$regs[2]); } break; // Functions that take one or two arguments case 'log': case 'round': - if ($regs[5] || empty($regs[3])) { + if (!empty($regs[5]) || empty($regs[3])) { return get_string('functiontakesoneortwoargs','quiz',$regs[2]); } break; // Functions that must have two arguments case 'atan2': case 'fmod': case 'pow': - if ($regs[5] || empty($regs[4])) { + if (!empty($regs[5]) || empty($regs[4])) { return get_string('functiontakestwoargs', 'quiz', $regs[2]); } break; diff --git a/question/type/numerical/questiontype.php b/question/type/numerical/questiontype.php index e1ae906fcf..2deeec97c0 100644 --- a/question/type/numerical/questiontype.php +++ b/question/type/numerical/questiontype.php @@ -22,6 +22,11 @@ require_once("$CFG->dirroot/question/type/shortanswer/questiontype.php"); */ class question_numerical_qtype extends question_shortanswer_qtype { + public $virtualqtype = false; + public $unitpenalty = 0; + public $raw_unitgrade = 0 ; + public $raw_unitpenalty = 0 ; + public $valid_numerical_unit = true ; function name() { return 'numerical'; } @@ -40,6 +45,7 @@ class question_numerical_qtype extends question_shortanswer_qtype { // the question table as is usually the case for qtype // specific tables. global $CFG, $DB, $OUTPUT; + $this->get_numerical_options($question); if (!$question->options->answers = $DB->get_records_sql( "SELECT a.*, n.tolerance " . "FROM {question_answers} a, " . @@ -64,9 +70,30 @@ class question_numerical_qtype extends question_shortanswer_qtype { } } } + + return true; + } + function get_numerical_options(&$question) { + global $DB; + if (!$options = $DB->get_record('question_numerical_options', array('question' => $question->id))) { + // echo $OUTPUT->notification('Error: Missing question options for numerical question'.$question->id.'!'); + // return false; + $question->options->unitgradingtype = 0; + $question->options->unitpenalty = 0; + $question->options->showunits = 0 ; + $question->options->unitsleft = 0 ; + $question->options->instructions = '' ; + } else { + $question->options->unitgradingtype = $options->unitgradingtype; + $question->options->unitpenalty = $options->unitpenalty; + $question->options->showunits = $options->showunits ; + $question->options->unitsleft = $options->unitsleft ; + $question->options->instructions = $options->instructions ; + } + + return true; } - function get_numerical_units(&$question) { global $DB; if ($units = $DB->get_records('question_numerical_units', array('question' => $question->id), 'id ASC')) { @@ -177,7 +204,10 @@ class question_numerical_qtype extends question_shortanswer_qtype { $DB->delete_records('question_numerical', array('id' => $oo->id)); } } - + $result = $this->save_numerical_options($question); + if (isset($result->error)) { + return $result; + } // Report any problems. if (!empty($result->notice)) { return $result; @@ -185,6 +215,56 @@ class question_numerical_qtype extends question_shortanswer_qtype { return true; } + function save_numerical_options(&$question) { + global $DB; + $result = new stdClass; + // numerical options + $update = true ; + $options = $DB->get_record("question_numerical_options", array("question" => $question->id)); + if (!$options) { + $update = false; + $options = new stdClass; + $options->question = $question->id; + } + if(isset($question->unitgradingtype)){ + $options->unitgradingtype = $question->unitgradingtype; + }else { + $options->unitgradingtype = 0 ; + } + if(isset($question->unitpenalty)){ + $options->unitpenalty = $question->unitpenalty; + }else { + $options->unitpenalty = 0 ; + } + if(isset($question->showunits)){ + $options->showunits = $question->showunits; + }else { + $options->showunits = 0 ; + } + if(isset($question->unitsleft)){ + $options->unitsleft = $question->unitsleft; + }else { + $options->unitsleft = 0 ; + } + if(isset($question->instructions)){ + $options->instructions = trim($question->instructions); + }else { + $options->instructions = '' ; + } + if ($update) { + if (!$DB->update_record("question_numerical_options", $options)) { + $result->error = "Could not update numerical question options! (id=$options->id)"; + return $result; + } + } else { + if (!$DB->insert_record("question_numerical_options", $options)) { + $result->error = "Could not insert numerical question options!"; + return $result; + } + } + return $result; + } + function save_numerical_units($question) { global $DB; $result = new stdClass; @@ -216,7 +296,82 @@ class question_numerical_qtype extends question_shortanswer_qtype { return $result; } - /** + function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) { + $state->responses = array(); + $state->responses['answer'] = ''; + $state->responses['unit'] = ''; + /* if ($question->options->showunits == 1){ + $state->responses['unit'] = '0'; + }*/ + + return true; + } + function restore_session_and_responses(&$question, &$state) { + if(false === strpos($state->responses[''], '|||||')){ + // temporary + $state->responses['answer']= $state->responses['']; + $state->responses['unit'] = ''; + split_old_answer($state->responses[''], $question->options->units, $state->responses['answer'] ,$state->responses['unit'] ); + }else { + $responses = explode('|||||', $state->responses['']); + $state->responses['answer']= $responses[0]; + $state->responses['unit'] = $responses[1]; + } + // echo "
restore response $responses ||
";print_r($state);echo ""; + + /* + if ($question->options->showunits == 1 && isset($question->options->units)){ + $state->responses['unit']=$this->find_unit_index($question,$state->responses['unit']); + }*/ + return true; + } + + function find_unit_index(&$question,$value){ + $length = 0; + $goodkey = 0 ; + foreach ($question->options->units as $key => $unit){ + if($unit->unit ==$value ) { + return $key ; + } + } + return 0 ; + } + + function split_old_answer($rawresponse, $units, &$answer ,&$unit ) { + $answer = $rawresponse ; + // remove spaces and normalise decimal places. + $search = array(' ', ','); + $replace = array('', '.'); + $rawresponse = str_replace($search, $replace, trim($rawresponse)); + if (preg_match('~^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$~', + $rawresponse, $responseparts)) { + $unit = $responseparts[5] ; + $answer = $responseparts[1] ; + } + return ; + } + + + function save_session_and_responses(&$question, &$state) { + global $DB; + // echo "
save session
";print_r($state);echo ""; + + $responses = ''; + if(isset($state->responses['unit']) && isset($question->options->units[$state->responses['unit']])){ + $responses = $state->responses['answer'].'|||||'.$question->options->units[$state->responses['unit']]->unit; + }else if(isset($state->responses['unit'])){ + $responses = $state->responses['answer'].'|||||'.$state->responses['unit'] ; + }else { + $responses = $state->responses['answer'].'|||||'; + } + // Set the legacy answer field + if (!$DB->set_field('question_states', 'answer', $responses, array('id' => $state->id))) { + return false; + } + return true; + } + +/** * Deletes question from the question-type specific tables * * @return boolean Success/Failure @@ -225,13 +380,36 @@ class question_numerical_qtype extends question_shortanswer_qtype { function delete_question($questionid) { global $DB; $DB->delete_records("question_numerical", array("question" => $questionid)); + $DB->delete_records("question_numerical_options", array("question" => $questionid)); $DB->delete_records("question_numerical_units", array("question" => $questionid)); return true; } + function compare_responses(&$question, $state, $teststate) { - if (isset($state->responses['']) && isset($teststate->responses[''])) { - return $state->responses[''] == $teststate->responses['']; + if ($question->options->showunits == 1 && isset($question->options->units) && isset($question->options->units[$state->responses['unit']] )){ + $state->responses['unit']=$question->options->units[$state->responses['unit']]->unit; + }; + + + $responses = ''; + $testresponses = ''; + if (isset($state->responses['answer'])){ + $responses = $state->responses['answer']; + } + if (isset($state->responses['unit'])){ + $responses .= $state->responses['unit']; + } + if (isset($teststate->responses['answer'])){ + $testresponses = $teststate->responses['answer']; + } + if (isset($teststate->responses['unit'])){ + $testresponses .= $teststate->responses['unit']; + } + if ( isset($responses) && isset($testresponses )) { + // echo "
compare response $responses || $testresponses
";print_r($state);echo ""; + + return $responses == $testresponses ; } return false; } @@ -246,8 +424,23 @@ class question_numerical_qtype extends question_shortanswer_qtype { if ($answer->answer === '*') { return true; } - + // echo "
test response numerical state
";print_r($state);echo ""; + // echo "
test response numerical question
";print_r($question);echo ""; + + if( isset($state->responses['unit']) && isset($question->options->units[$state->responses['unit']])){ + $state->responses['']=$state->responses['answer'].$question->options->units[$state->responses['unit']]->unit; + // echo "
test responses valid unit
"; + }else if(isset($state->responses['unit'])){ + $state->responses['']= $state->responses['answer'].$state->responses['unit'] ;// why? + } + // echo "test response numerical state before apply
";print_r($state);echo ""; + $response = $this->apply_unit($state->responses[''], $question->options->units); + // $this->valid_numerical_unit = $this->valid_unit($state->responses[''], $question->options->units); + // if ($this->valid_numerical_unit) echo "
test responses valid unit
"; + // if (!$this->valid_numerical_unit) echo "test responses not valid unit
"; + // echo "state response test $response
";print_r($state);echo ""; + // $this->raw_unitpenalty = 0.1 ; if ($response === false) { return false; // The student did not type a number. @@ -258,6 +451,67 @@ class question_numerical_qtype extends question_shortanswer_qtype { return ($answer->min <= $response && $response <= $answer->max); } + function grade_responses(&$question, &$state, $cmoptions) { + // The default implementation uses the test_response method to + // compare what the student entered against each of the possible + // answers stored in the question, and uses the grade from the + // first one that matches. It also sets the marks and penalty. + // This should be good enought for most simple question types. + // echo "
grade responses
";print_r($state->responses);echo ""; + + //first the split response from unit choice display is converted as + // standard numerical response value.unit + /* if (!empty($question->options->showunits) && isset($state->responses['unit'])){ + $state->responses[''] .= $question->options->units[$state->responses['unit']]->unit ; + } + */ + //to apply the unit penalty we need to analyse the response in a more complex way + //the apply_unit() function analysis could be used to obtain the infos + // however it is used to detect good or bad numbers but also + // gives false + $state->raw_grade = 0; + foreach($question->options->answers as $answer) { + if($this->test_response($question, $state, $answer)) { + $state->raw_grade = $answer->fraction; + $this->raw_unitgrade = $answer->fraction; + if( $question->options->showunits == 3) { + $this->valid_numerical_unit == true ; + }else { + $this->valid_numerical_unit = $this->valid_unit($state->responses[''], $question->options->units); + } + break; + } + } + // if ($this->valid_numerical_unit) echo "
grade responses valid unit
"; + // if (!$this->valid_numerical_unit) echo "grade responses not valid unit
"; + // apply unit penalty + $this->raw_unitpenalty = 0 ; + if(!empty($question->options->unitpenalty)&& !$this->valid_numerical_unit ){ + if($question->options->unitgradingtype == 1){ + $this->raw_unitpenalty = $question->options->unitpenalty* $state->raw_grade ; + }else { + $this->raw_unitpenalty = $question->options->unitpenalty* $question->maxgrade; + } + $state->raw_grade -= $question->options->unitpenalty ; + } + // echo "grade responses
";print_r($state->responses);echo ""; + + // $this->raw_unitpenalty = $question->options->unitpenalty ; + // Make sure we don't assign negative or too high marks. + // $state->raw_grade -= $question->options->unitpenalty ; + $state->raw_grade = min(max((float) $state->raw_grade, + 0.0), 1.0) * $question->maxgrade; + + // Update the penalty. + $state->penalty = $question->penalty * $question->maxgrade; + + // mark the state as graded + $state->event = ($state->event == QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE; + + return true; + } + + function get_correct_responses(&$question, &$state) { $correct = parent::get_correct_responses($question, $state); $unit = $this->get_default_numerical_unit($question); @@ -293,6 +547,22 @@ class question_numerical_qtype extends question_shortanswer_qtype { $result->responses = $answers; return $result; } + function get_actual_response($question, $state) { + // echo "
state response numerical GET ACTUAL RESPONSE $question->id $question->qtype
";print_r($state);echo ""; + if (!empty($state->responses) && !empty($state->responses[''])) { + if(false === strpos($state->responses[''], '|||||')){ + $responses[] = $state->responses['']; + }else { + $resp = explode('|||||', $state->responses['']); + $responses[] = $resp[0].$resp[1]; + } + } else { + $responses[] = ''; + } + + return $responses; + } + function get_tolerance_interval(&$answer) { // No tolerance @@ -374,6 +644,81 @@ class question_numerical_qtype extends question_shortanswer_qtype { if (isset($tmpunits[$responseparts[5]])) { // Valid number with unit. return (float)$responseparts[1] / $tmpunits[$responseparts[5]]; + } else { + // Valid number with invalid unit. + return (float)$responseparts[1]; + } + + } else { + // Valid number without unit. + return (float)$responseparts[1]; + } + } + // Invalid number. Must be wrong. + return false; + } + function edit_numerical_options(&$mform, &$that){ + $mform->addElement('header', 'unithandling', get_string("Units handling", 'qtype_numerical')); + $currentgrp1 = array(); + + $currentgrp1[] =& $mform->createElement('text', 'unitpenalty', get_string('Penalty for bad unit', 'qtype_numerical') , + array('size' => 3)); + $currentgrp1[] =& $mform->createElement('static', 'penalty1','hello', get_string('as decimal fraction (0-1) of', 'qtype_numerical')); + $mform->addGroup($currentgrp1, 'penaltygrp', get_string('Penalty for bad unit', 'qtype_numerical'), null, false); + $mform->setType('unitpenalty', PARAM_NUMBER); + //$mform->addRule('unitpenalty', null, 'required', null, 'client'); + $mform->setDefault('unitpenalty', 0.1); + $currentgrp = array(); + $currentgrp[] =& $mform->createElement('radio', 'unitgradingtype', 'or', get_string('question grade', 'qtype_numerical'),1); + $currentgrp[] =& $mform->createElement('radio', 'unitgradingtype', '', get_string(' response grade', 'qtype_numerical'),2); + $mform->setDefault('unitgradingtype', 1); + $mform->addGroup($currentgrp, 'penaltychoicegrp', '',' or ', false); + $mform->setHelpButton('penaltychoicegrp', array('penaltygrp', get_string('unitpenalty', 'qtype_numerical'), 'qtype_numerical')); + $mform->addElement('radio', 'showunits', 'Edit unit ', get_string('Editable text input element', 'qtype_numerical'),0); + $mform->addElement('radio', 'showunits', 'Select units ', get_string('Choice radio element', 'qtype_numerical'),1); + $mform->addElement('radio', 'showunits', 'Display unit ', get_string('NON editable text of Unit No1', 'qtype_numerical'),2); + $mform->addElement('radio', 'showunits', 'No unit display', get_string("Only numerical answer will be graded leave Unit No1 empty", 'qtype_numerical'),3); + $mform->setDefault('showunits', 0); + $currentgrp = array(); + $leftgrp[] =& $mform->createElement('radio', 'unitsleft', '', get_string('left as $1.00', 'qtype_numerical'),1); + $leftgrp[] =& $mform->createElement('radio', 'unitsleft', '', get_string('rigth as 1.00cm', 'qtype_numerical'),0); + $mform->addGroup($leftgrp, 'unitsleft', 'Unit position',' or ', false); + $mform->setDefault('unitsleft', 0); + $mform->addElement('htmleditor', 'instructions', get_string('instructions', 'quiz'), + array('rows' => 10, 'course' => $that->coursefilesid)); + $mform->setType('instructions', PARAM_RAW); + $mform->setHelpButton('instructions', array('instructions', get_string('instructions', 'quiz'), 'quiz')); + + + } + + function print_question_grading_details(&$question, &$state, $cmoptions, $options) { + // echo "
state uestion_grading_details $question->id $question->qtype
";print_r($state);echo ""; + + parent::print_question_grading_details(&$question, &$state, $cmoptions, $options); + + } + + function valid_unit($rawresponse, $units) { + // Make units more useful + $tmpunits = array(); + foreach ($units as $unit) { + $tmpunits[$unit->unit] = $unit->multiplier; + } + // remove spaces and normalise decimal places. + $search = array(' ', ','); + $replace = array('', '.'); + $rawresponse = str_replace($search, $replace, trim($rawresponse)); + + // Apply any unit that is present. + if (preg_match('~^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$~', + $rawresponse, $responseparts)) { + + if (!empty($responseparts[5])) { + + if (isset($tmpunits[$responseparts[5]])) { + // Valid number with unit. + return true ; //(float)$responseparts[1] / $tmpunits[$responseparts[5]]; } else { // Valid number with invalid unit. Must be wrong. return false; @@ -381,7 +726,7 @@ class question_numerical_qtype extends question_shortanswer_qtype { } else { // Valid number without unit. - return (float)$responseparts[1]; + return false ; //(float)$responseparts[1]; } } // Invalid number. Must be wrong. @@ -413,6 +758,22 @@ class question_numerical_qtype extends question_shortanswer_qtype { $status = question_backup_numerical_units($bf,$preferences,$question,7); $status = fwrite ($bf,end_tag("NUMERICAL",$level,true)); } + $status = question_backup_numerical_options($bf,$preferences,$question,$level); + /* $numerical_options = $DB->get_records("question_numerical_options",array("questionid" => $question),"id"); + if ($numerical_options) { + //Iterate over each numerical_option + foreach ($numerical_options as $numerical_option) { + $status = fwrite ($bf,start_tag("NUMERICAL_OPTIONS",$level,true)); + //Print numerical_option contents + fwrite ($bf,full_tag("INSTRUCTIONS",$level+1,false,$numerical_option->instructions)); + fwrite ($bf,full_tag("SHOWUNITS",$level+1,false,$numerical_option->showunits)); + fwrite ($bf,full_tag("UNITSLEFT",$level+1,false,$numerical_option->unitsleft)); + fwrite ($bf,full_tag("UNITGRADINGTYPE",$level+1,false,$numerical_option->unitgradingtype)); + fwrite ($bf,full_tag("UNITPENALTY",$level+1,false,$numerical_option->unitpenalty)); + $status = fwrite ($bf,end_tag("NUMERICAL_OPTIONS",$level,true)); + } + }*/ + //Now print question_answers $status = question_backup_answers($bf,$preferences,$question); } @@ -471,6 +832,9 @@ class question_numerical_qtype extends question_shortanswer_qtype { //Now restore numerical_units $status = question_restore_numerical_units ($old_question_id,$new_question_id,$num_info,$restore); + //Now restore numerical_options + $status = question_restore_numerical_options ($old_question_id,$new_question_id,$num_info,$restore); + if (!$newid) { $status = false; } diff --git a/question/type/shortanswer/questiontype.php b/question/type/shortanswer/questiontype.php index 92d3a29ebb..061fdec38e 100644 --- a/question/type/shortanswer/questiontype.php +++ b/question/type/shortanswer/questiontype.php @@ -98,6 +98,11 @@ class question_shortanswer_qtype extends default_questiontype { function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG; + // $state->raw_unitgrade = 2 ; + // echo "
state
";print_r($state);echo ""; + // echo "
cmoptions
";print_r($cmoptions);echo ""; + // echo "
options
";print_r($options);echo ""; + // echo "
questionoptions
";print_r($question);echo ""; /// This implementation is also used by question type 'numerical' $readonly = empty($options->readonly) ? '' : 'readonly="readonly"'; $formatoptions = new stdClass; @@ -128,6 +133,7 @@ class question_shortanswer_qtype extends default_questiontype { if ($options->feedback) { $class = question_get_feedback_class(0); $feedbackimg = question_get_feedback_image(0); + //this is OK for the first answer with a good response foreach($question->options->answers as $answer) { if ($this->test_response($question, $state, $answer)) { @@ -310,6 +316,10 @@ class question_shortanswer_qtype extends default_questiontype { $grade->cur = question_format_grade($cmoptions, $state->last_graded->grade); $grade->max = question_format_grade($cmoptions, $question->maxgrade); $grade->raw = question_format_grade($cmoptions, $state->last_graded->raw_grade); + $grade->numerical = ""; + if($this->raw_unitpenalty > 0.0 ){ + $grade->numerical = "This submission attracted a penalty of $this->raw_unitpenalty for bad unit." ;//question_format_grade($cmoptions, $state->last_graded->raw_grade); + } // let student know wether the answer was correct $class = question_get_feedback_class($state->last_graded->raw_grade / @@ -336,7 +346,9 @@ class question_shortanswer_qtype extends default_questiontype { if (($state->last_graded->raw_grade < $question->maxgrade) and (QUESTION_EVENTCLOSEANDGRADE != $state->event)) { if ('' !== $state->last_graded->penalty && ((float)$state->last_graded->penalty) > 0.0) { // A penalty was applied so display it - echo ' '; + echo ' '.$grade->numerical; + //print_string('gradingdetailspenalty', 'quiz', question_format_grade($cmoptions, $this->raw_unitpenalty)); + echo ' '; print_string('gradingdetailspenalty', 'quiz', question_format_grade($cmoptions, $state->last_graded->penalty)); } else { /* No penalty was applied even though the answer was