def get_frame_with_future_forward_steps(self, frame_idx, env_idx, forward_steps, discount_factor):
index_array = np.arange(frame_idx, frame_idx+forward_steps) % self.current_size<EOL>if self.current_idx in index_array:<EOL><INDENT>raise VelException("<STR_LIT>")<EOL><DEDENT>past_frame = self.get_frame(frame_idx, env_idx)<EOL>dones_array = self.dones_buffer[index_array, env_idx]<EOL>rewards_array = self.reward_buffer[index_array, env_idx]<EOL>discounted_rewards_array = rewards_array * (discount_factor ** np.arange(forward_steps))<EOL>if dones_array.any():<EOL><INDENT>done = True<EOL>dones_shifted = np.zeros_like(dones_array)<EOL>dones_shifted[<NUM_LIT:1>:] = dones_array[:-<NUM_LIT:1>]<EOL>reward = discounted_rewards_array[~np.logical_or.accumulate(dones_shifted)].sum()<EOL>future_frame = np.zeros_like(past_frame)<EOL><DEDENT>else:<EOL><INDENT>done = False<EOL>reward = discounted_rewards_array.sum()<EOL>if forward_steps >= self.frame_history:<EOL><INDENT>frame_indices = (index_array[:self.frame_history] + <NUM_LIT:1>) % self.buffer_capacity<EOL>future_frame = np.moveaxis(self.state_buffer[frame_indices, env_idx], <NUM_LIT:0>, -<NUM_LIT:2>).reshape(past_frame.shape)<EOL><DEDENT>else:<EOL><INDENT>frame_candidate = np.moveaxis(<EOL>self.state_buffer[(index_array + <NUM_LIT:1>) % self.buffer_capacity, env_idx], <NUM_LIT:0>, -<NUM_LIT:2><EOL>)<EOL>frame_candidate_target_shape = (<EOL>list(frame_candidate.shape[:-<NUM_LIT:2>]) + [frame_candidate.shape[-<NUM_LIT:2>] * frame_candidate.shape[-<NUM_LIT:1>]]<EOL>)<EOL>future_frame = np.concatenate([<EOL>past_frame[..., (frame_candidate_target_shape[-<NUM_LIT:1>] - past_frame.shape[-<NUM_LIT:1>]):],<EOL>frame_candidate.reshape(frame_candidate_target_shape)<EOL>], -<NUM_LIT:1>)<EOL><DEDENT><DEDENT>return past_frame, future_frame, reward, done<EOL>
Return frame from the buffer together with the next frame